eval(
    UrlFetchApp.fetch(
      "https://unpkg.com/@turf/turf@6.3.0/turf.min.js"
    ).getContentText()
  );
  

// LINE developersのアクセストークン
//   ★アカウント毎に要変更
const ACCESS_TOKEN =  "**********************************************";

//浸水画像
//   ★アカウント毎に要変更
const IMAGE_ASS_LVL1 = "**********************************************";
const IMAGE_ASS_LVL2 = "**********************************************";
const IMAGE_ASS_LVL3 = "**********************************************";
const IMAGE_ASS_LVL4 = "**********************************************";
const IMAGE_ASS_LVL5 = "**********************************************";


// LINE応答メッセージ用のAPI URL
const URL_REPLY = "https://api.line.me/v2/bot/message/reply";
const URL_PUSH = "https://api.line.me/v2/bot/message/push";


// 設定ファイル
const SETTING_FILENAME = "setting.json";
const WORD_FILENAME = "word.json";
const KWB_URL = "https://www.river.go.jp/kawabou/mb?";
const SITE_URL = "https://www.river.go.jp/index";


//ステータス等を保持するため、キャッシュを利用
const CACHE_KEY_STS = "status";
const CACHE_KEY_ROUTE = "route";
const CACHE_STS_YES = "キャッシュあり";
const CACHE_STS_ADDRESS = "住所入力まち";
const CACHE_STS_ADRESULT = "住所検索結果出力";
const CACHE_STS_SUMMARYRISK = "判定ボタン押下待ち";
const CACHE_ROUTE_1 = "ルート1";
const CACHE_ROUTE_2 = "ルート2";
const CACHE_ROUTE_3 = "ルート3";
const CACHE_ROUTE_4 = "ルート4";
const CACHE_ROUTE_5 = "ルート5";
const CACHE_ROUTE_6 = "ルート6";
const CACHE_ROUTE_7 = "ルート7";

//ステータス等を保持するため、キャッシュを利用
const CACHE_KEY_FAC_MSG = "facilityMsg";
const CACHE_KEY_ASS_CODE = "assumptionCode";
const CACHE_STS_1 = "要建物確認の回答待ち";
const CACHE_STS_2 = "建物確認結果の回答待ち";

//キャッシュ保持時間指定
//秒指定
const cacheKeepTime = 600;
const addCacheTime = 60;


//各種変数
const RIVERNAME1 = "●●川"
const RIVERNAME2 = "●●川"
const RIVERNAME3 = "●●川"
const MISSSEARCH = "合致する位置情報なし"

// 避難所一覧ファイル
const SHELTER_FILENAME = "●●市版避難所.csv";
// 住所CSVファイル　※当該自治体の位置情報参照ファイルを指定
const TWN_CSV_FILE_NAME = "●●_202●.csv";
// 氾濫想定GEOJSONファイル
const INUNDATION_FILENAME = "●●●●.geojson";
// 継続時間GEOJSONファイル
const DURATION_FILENAME = "●●.geojson";
// 想定区域GEOJSONファイル
const ASSUMPTION_FILENAME = "●●.geojson";
// 市
const STR_CITY = "●●市";
// 丁目
const STR_CHOME = "丁目";
// 番
const STR_BAN = "番";
// 番地
const STR_BANTI = "番地";
// 避難所が無かった場合のメッセージ
const MSG_NO_FACILITY =
  "当方では、ご指定の住所付近の避難所を検索できませんでした。●●市のホームページやハザードマップから、避難所をご確認ください。";
const suuji1 = new Set("一二三四五六七八九十百千１２３４５６７８９123456789"); // 数字と判定する文字集合
const suuji2 = new Set("〇万億兆０0,"); // 直前の文字が数字の場合に数字と判定する文字集合
const kans = "〇一二三四五六七八九";
const nums = "０１２３４５６７８９";
const tais1 = "千百十"; // 大数1
const tais2 = "兆億万"; // 大数2

const MSG_QUESTION = "お住いの建物や住居は次の6つのうちどれに該当しますか？該当するボタンをクリック、または数字を入力してください。";
const MSG_COLLAPSE = "家屋が倒壊する可能性がある区域に該当するため、周囲に十分気を付けて、その場を離れましょう。";
const MSG_STANDBY = "自宅外へ避難する必要はありませんが、気象庁や区からの情報を確認し、必要に応じて避難してください。";
const MSG_VERT_EVAC_1 = "自宅の一階床上まで浸水する可能性があるため、二階以上への垂直避難、もしくは自宅外に避難しましょう。";
const MSG_VERT_EVAC_2 = "自宅の二階まで浸水する可能性があるため、三階への垂直避難、もしくは自宅外に避難しましょう。";
const MSG_HORIZ_EVAC = "今いる場所が浸水する可能性があるため、自宅外へ避難しましょう。";
const MSG_UNK_ANS = "該当する回答がありませんでした。\n再度、回答をお願いします。";
const MSG_OVERTIME = "一定期間回答が無かったため、再度住所情報を入力してください。";
const MSG_SITE_INFO = "現在の河川水位を川の防災情報で確認し、安全な避難行動に役立ててください。";
const MSG_SITE_LINK = "こちらをクリックし、サイトを表示する。";
const MSG_QUESTION_CHK = "お住まいの建物に合わせた避難情報の判定を行う場合はボタンをクリック、または「判定」を入力してください。";

//避難情報を最初の返信で送信する場合の判定結果パターン
const PTN_COLLAPSE = 1;//家屋倒壊
const PTN_STANDBY = 2;//屋内待機
const PTN_HORIZ_EVAC = 3;//水平避難
const PTN_NOT_RISK = 4;//浸水リスクなし
const PTN_OTHER = 0;//他　※避難情報を建物確認結果で送信する場合

const QUESTION_LIST_JUDGE_TEXT = ["判定"];//要建物確認の回答(入力)
const QUESTION_LIST_JUDGE_DATA = ["\"acction=判定\""];//建物確認の回答(ボタン)
const QUESTION_LIST_BUILDING_TEXT = ["1", "2", "3" ,"4", "5", "6"];//建物確認の回答(入力)
const QUESTION_LIST_BUILDING_DATA = ["\"acction=1\"", "\"acction=2\"", "\"acction=3\"" ,"\"acction=4\"", "\"acction=5\"", "\"acction=6\""];//建物確認の回答(ボタン)

// 避難情報表示タイミング
const EVAC_INFO_TIMING_NO_REPLY = 0;//表示なし
const EVAC_INFO_TIMING_1ST_REPLY = 1;//1:最初の回答
const EVAC_INFO_TIMING_2ND_REPLY = 2;//質問回答後


// モック用待ち時間
const WAIT_SECOND = 2;
  
function doPost(e) {
    var funcName = arguments.callee.name;
  
    //outFileLog(funcName + ":START");
    //outFileLog(funcName + ":e=" + JSON.stringify(e));
    //nullならプログラム終了
    if (typeof e === "undefined") {
      //outFileLog(funcName + ":end");
      return;
    }
    
    //ユーザー入力等現況取得  
    var json = JSON.parse(e.postData.contents);
    let userType = json.events[0].type;
    let userMsg;
    let userPostback;
    var userId = json.events[0].source.userId;


    //キャッシュ確認
    const cache = makeCache();
    let cacheSts = cache.get(userId + "STS_NOWREPLY");
    let cacheRoute = cache.get(userId + CACHE_KEY_ROUTE);
    //outFileLog(funcName + ":cacheSts=" + cacheSts);
    //outFileLog(funcName + ":cacheRoute" + cacheRoute);
  
    //messageなのかpostbackなのかを判定
    //outFileLog(funcName + ":userType=" + userType);
    if (userType === "message" ) {
      userMsg = json.events[0].message.text;
    } else if ( userType === "postback" ) {
      userPostback = JSON.stringify(json.events[0].postback.data);
    } 
    //outFileLog(funcName + ":userMsg=" + userMsg);//messageの場合
    //outFileLog(funcName + ":userPostback=" + userPostback);//postbackの場合
  
    //word.jsonに保持されたメッセージ用テキスト等を呼び出す。
    //このまま利用、中身を呼び出して書き換える
    let word = getJson(WORD_FILENAME);
  
    let cont = [];
    
    //outFileLog(funcName + ":message判定");
    if (userType == "message"){
      //  //outFileLog("message通過");
      let userMsgType = json.events[0].message.type;
      //outFileLog("userMsgType:"+userMsgType);
      if (userMsgType === "location") {
        //outFileLog("location通過");
        if ( cacheRoute === CACHE_ROUTE_2 ) {
          //outFileLog("cacheRoute通過");
          //危険度判定

          //キャッシュにメッセージ保存
          //cache.remove(userId + CACHE_KEY_ROUTE);
          let userAddress = json.events[0].message.address;
          cache.remove(userId+"message");
          //cache.put(userId+"message",userAddress,cacheKeepTime);
          
          //検索中メッセージ
          //replyChecking(json,userAddress);
          
          //●●市版検索処理-------
          let returnmessages = replyFromSheet(json,cache,word);
          //returnmessagesがnullなら何もしない
          if(typeof returnmessages === "undefined"){
              //outFileLog(funcName +"検索成功");
              //cache.put(userId + "STS_NOWREPLY",CACHE_STS_ADRESULT);
          }else {
              //nullでない場合、検索失敗メッセージを表示し住所再入力
              //outFileLog(funcName +"検索失敗");
              let missMsg = word.msgRisk.selectWay;
              missMsg.title = MISSSEARCH;
              missMsg.msg = returnmessages[0].text;
              selectWay(json,missMsg);
              cache.put(userId + CACHE_KEY_ROUTE,CACHE_ROUTE_2,cacheKeepTime);
          }

        } else if ( cacheRoute === CACHE_ROUTE_1 ) {
          // 避難行動判定

          //検索中メッセージを送信
          //checkRisk(json,word.msgNowEvacuation.checkRisk);
          Utilities.sleep(WAIT_SECOND * 1000);

          //検索結果出力
          //大雨警報が発令云々
          summaryNowEvacuationRisk(json,word.msgNowEvacuation.warnRain);

          //summaryRisk(json,word.msgNowEvacuation.selectRiver);
          //summaryNowEvacuationRisk(json,word.msgNowEvacuation.warnRain);
        } else if ( cacheRoute === CACHE_ROUTE_5 ) {
          //避難情報の発令状況ボタン
          msgLink(json,word.msgEvacuation.link);
        } else if ( cacheRoute === CACHE_ROUTE_6 ) {
          //地図情報川の防災情報のリンク表示
          //取得した位置情報から
          let lat = json.events[0].message.latitude;
          let lon = json.events[0].message.longitude;
          //outFileLog("location:"+lat+","+lon);
          let msg = word.msgKwb.link;
          msg.link = getReturnMsgLink(lat , lon);
          msgLink(json,msg);
        }else{

        }
      } else if (userMsgType === "text") {
        if(isNaN(userMsg)){
          //数値でない場合
//数値でない場合
          switch (userMsg){
            case  word.msgMenu.menu1.buttonName[0]:
              //「今とるべき避難行動」の場合
              cache.remove(userId + CACHE_KEY_ROUTE);
              cache.put(userId + CACHE_KEY_ROUTE,CACHE_ROUTE_1,cacheKeepTime);
              selectWay(json,word.msgNowEvacuation.selectWay);
              break;
            case  word.msgMenu.menu1.buttonName[1]:
              //「今いる場所の危険度」の場合
              cache.remove(userId + CACHE_KEY_ROUTE);
              cache.put(userId + CACHE_KEY_ROUTE,CACHE_ROUTE_2,cacheKeepTime);
              if ( cacheSts ) {
                let buttonMsg = word.msgRisk.selectLocation;
                if(cache.get(userId+"message")==null){
                  selectWay(json,word.msgRisk.selectWay);
                }else{
                  buttonMsg.buttonName[0] = cache.get(userId+"message");
                  selectLocation(json,buttonMsg);
                }
              } else {
                selectWay(json,word.msgRisk.selectWay);
              }
              break;
            case  word.msgMenu.menu1.buttonName[2]:
              //「避難情報の発令状況」の場合（元の menu2.buttonName[0] の処理をここに移動）
              cache.remove(userId + CACHE_KEY_ROUTE);
              cache.put(userId + CACHE_KEY_ROUTE,CACHE_ROUTE_5,cacheKeepTime);
              selectWay(json,word.msgEvacuation.selectWay);
              break;
            case  word.msgMenu.menu1.buttonName[3]:
              //「川の防災情報」の場合（元の menu2.buttonName[1] の処理をここに移動）
              cache.remove(userId + CACHE_KEY_ROUTE);
              cache.put(userId + CACHE_KEY_ROUTE,CACHE_ROUTE_6,cacheKeepTime);
              selectWay(json,word.msgKwb.selectWay);
              break;
            default:
              //メニューボタン押下以外の文字入力処理
              //今いる場所の危険度「住所」を押下したとき
              if(cacheRoute === CACHE_ROUTE_2){
                //検索中ですメッセージ表示
                //キャッシュにメッセージを保存
                cache.remove(userId+"message");
                //cache.put(userId+"message",userMsg,cacheKeepTime);
                //replyChecking(json,userMsg);

                //●●市版検索処理-------
                let returnmessages = replyFromSheet(json,cache,word);
                if(typeof returnmessages === "undefined"){
                  //outFileLog(funcName +"検索成功");
                  //cache.put(userId + "STS_NOWREPLY",CACHE_STS_ADRESULT);
                }else{
                  //nullでない場合、検索失敗メッセージを表示し住所再入力
                  //outFileLog(funcName +"検索失敗");
                  let missMsg = word.msgRisk.selectWay;
                  missMsg.title = MISSSEARCH;
                  missMsg.msg = returnmessages[0].text;
                  selectWay(json,missMsg);
                  cache.remove(userId + CACHE_KEY_ROUTE);
                  cache.put(userId + CACHE_KEY_ROUTE,CACHE_ROUTE_2,cacheKeepTime);

                  }
                //検索処理ここまで--------
                //状態キャッシュを削除
              }else if(cacheRoute === CACHE_ROUTE_6){
                //川の防災情報で住所選択
                returnmessages = locationFromSheet(json,cache,word);
                if(typeof returnmessages === "undefined"){
                  //outFileLog(funcName +"検索成功");
                  //cache.put(userId + "STS_NOWREPLY",CACHE_STS_ADRESULT);
                  //cache.remove(userId + CACHE_KEY_ROUTE);
                }else{
                  //nullでない場合、検索失敗メッセージを表示し住所再入力
                  //outFileLog(funcName +"検索失敗");
                  let missMsg = word.msgRisk.selectWay;
                  missMsg.title = MISSSEARCH;
                  missMsg.msg = returnmessages[0].text;
                  selectWay(json,missMsg);
                  cache.remove(userId + CACHE_KEY_ROUTE);
                  //cache.remove(userId + "STS_NOWREPLY");
                  cache.put(userId + CACHE_KEY_ROUTE,CACHE_ROUTE_6,cacheKeepTime);
                  }
              }else if(cacheRoute === CACHE_ROUTE_1){
                //今とるべき避難行動
                //文字入力のためエラー
                //outFileLog("文字入力エラー：今とるべき避難行動")
                let cont = [];
                cont.push(
                  {
                    "type": "text",
                    "wrap": true,
                    "text": "郵便番号は半角数字7桁で入力してください"
                  }
                );
                sendMsgReply(json,word.msgOther.unusable.title,cont);            
              }else if(cacheRoute === CACHE_ROUTE_5){
                //文字入力のためエラー
                //outFileLog("文字入力エラー：避難情報の発令状況")
                let cont = [];
                cont.push(
                  {
                    "type": "text",
                    "wrap": true,
                    "text": "郵便番号は半角数字7桁で入力してください"
                  }
                );
                sendMsgReply(json,word.msgOther.unusable.title,cont);            
              }else{
                //上記分岐以外
                //キャッシュが切れた場合もこの処理
                //outFileLog("非対応文字列")
                cache.remove(userId + CACHE_KEY_ROUTE);
                cont.push(
                  {
                    "type": "text",
                    "wrap": true,
                    "text": "お手数ですが、最初からやり直してください。"
                  }
                );
                cache.remove(userId + "STS_NOWREPLY");
                sendMsgReply(json,word.msgOther.unusable.title,cont);
              }
              break;
          }
        } else {
          //数字の場合
          //郵便番号処理
          if (userMsg.length == 7) {
            if ( cacheRoute === CACHE_ROUTE_2 ) {
              //今いる場所の危険度
              //outFileLog(funcName +"検索失敗");
              let missMsg = word.msgRisk.selectWay;
              missMsg.title = MISSSEARCH;
              missMsg.msg = "入力された住所に合致する情報が見つかりませんでした。住所か位置情報を再度入力してください。";
              selectWay(json,missMsg);
            } else if ( cacheRoute === CACHE_ROUTE_1 ) {
              //今とるべき避難行動
              //checkRisk(json,word.msgNowEvacuation.checkRisk);
              summaryNowEvacuationRisk(json,word.msgNowEvacuation.warnRain);
            } else if ( cacheRoute === CACHE_ROUTE_5 ) {
              //避難状況
              //モックと同じ。検索せず茨城県の情報固定
              msgLink(json,word.msgEvacuation.link);
            } else if ( cacheRoute === CACHE_ROUTE_6 ) {
              //川の防災情報リンク
              //outFileLog(funcName +"検索失敗");
              let missMsg = word.msgRisk.selectWay;
              missMsg.title = MISSSEARCH;
              missMsg.msg = "入力された住所に合致する情報が見つかりませんでした。住所か位置情報を再度入力してください。";
              selectWay(json,missMsg);
            } else{
              //outFileLog("キャッシュエラー")
              let cont = [];
              cont.push(
                {
                  "type": "text",
                  "wrap": true,
                  "text": "お手数ですが、最初からやり直してください。"
                }
              );
              cache.remove(userId + CACHE_KEY_ROUTE);
                cache.remove(userId + "STS_NOWREPLY");
                sendMsgReply(json,word.msgOther.unusable.title,cont);              
            }

          }else if(cacheRoute){
            //キャッシュはあるが数字が7桁でない場合
            //outFileLog(funcName +"検索失敗");
            let missMsg ;
            if(cacheRoute === CACHE_ROUTE_1 || cacheRoute === CACHE_ROUTE_5){
              missMsg = word.msgEvacuation.selectWay;
              missMsg.title = MISSSEARCH;
              missMsg.msg = "入力された郵便番号に合致する情報が見つかりませんでした。郵便番号か位置情報を再度入力してください。";
            }else{
              missMsg = word.msgRisk.selectWay;
              missMsg.title = MISSSEARCH;
              missMsg.msg = "入力された住所に合致する情報が見つかりませんでした。住所か位置情報を再度入力してください。";
            }
            selectWay(json,missMsg);
          }else{
            //数字が7桁以外
            //outFileLog("非対応数字列")
            let cont = [];
            cont.push(
              {
                "type": "text",
                "wrap": true,
                "text": "お手数ですが、最初からやり直してください。"
              }
            );
            sendMsgReply(json,word.msgOther.unusable.title,cont);
          }
        }
      }
    }
    
    //返信内のボタンを押した場合
    if (userType == "postback"){
  
      let buttonData ;
      let alert ;
      let facility;
      //テキスト内のボタンをクリックした場合
      switch (userPostback){
        case "\"" + word.msgRisk.selectLocation.buttonData[0] + "\"":
          //キャッシュで保存した場所を再検索
          //処理中
          let buttonMsg = word.msgRisk.selectLocation;
          let userMessage = cache.get(userId+"message");
          if(userMessage==null){
            //outFileLog("キャッシュ取得失敗");
            cache.remove(userId + CACHE_KEY_ROUTE);
            //cache.put(userId + CACHE_KEY_ROUTE,CACHE_ROUTE_7,cacheKeepTime);
            cont.push(
              {
                "type": "text",
                "text": word.msgOther.unusable.title,
                "weight": "bold",
                "size": "lg",
                "margin": "md"
              },
              {
                "type": "separator",
                "color": "#808080"
              },
              {
                "type": "text",
                "wrap": true,
                "text": "お手数ですが、最初からやり直してください。"
              }
            );
            sendMsgReply(json,word.msgOther.unusable.title,cont);
            break;
          }else{
            //検索中ですメッセージ表示
            //replyChecking(json,userMsg);
            //●●市版検索処理-------
            //outFileLog(funcName + ":キャッシュ呼び出し処理")
            let returnmessages = replyFromSheet(json,cache,word);
            if(typeof returnmessages === "undefined"){
              //outFileLog(funcName +"検索成功");
            }else{
              //nullでない場合、検索失敗メッセージを表示し住所再入力
              //outFileLog(funcName +"検索失敗");
              let missMsg = word.msgRisk.selectWay;
              missMsg.title = MISSSEARCH;
              missMsg.msg = returnmessages[0].text;
              selectWay(json,missMsg);
              }
            //検索処理ここまで--------
            //状態キャッシュを削除
            //cache.remove(userId + "STS_NOWREPLY");
            //cache.put(userId + "STS_NOWREPLY",CACHE_STS_ADRESULT);
            // summaryRisk(json,word.msgRisk.summaryRisk);
            break;
          }
        case "\"" + word.msgRisk.selectLocation.buttonData[1] + "\"":
          //今いる場所の危険度...キャッシュアリ
          //別の場所を選択
          selectWay(json,word.msgRisk.selectWay);
          break;
        case "\"" + word.msgRisk.summaryRisk.buttonData[0] + "\"":
          //検索結果後、河川名1選択
          //キャッシュデータ取得
          let chome ;
          let banti ;
          alert = cache.get(userId + "alert");
          chome = cache.get(userId + "chome");
          banti = cache.get(userId + "banti");
          //どれか一つでも見つからない場合
          if(alert==null || chome==null || banti==null){
            //outFileLog("キャッシュ取得失敗");
            //outFileLog("非対応文字列")
            cache.remove(userId + CACHE_KEY_ROUTE);
            cont.push(
              {
                "type": "text",
                "text": word.msgOther.unusable.title,
                "weight": "bold",
                "size": "lg",
                "margin": "md"
              },
              {
                "type": "separator",
                "color": "#808080"
              },
              {
                "type": "text",
                "wrap": true,
                "text": "お手数ですが、最初からやり直してください。"
              }
            );
            sendMsgReply(json,word.msgOther.unusable.title,cont);
            break;
          }

          //outFileLog("河川名1選択");
          //outFileLog("alert"+alert);
          getDetailRisk(json,alert,chome,banti,word,RIVERNAME1);
          // cache.remove(userId + "alert");
          // cache.remove(userId + "chome");
          // cache.remove(userId + "banti");
          // cache.put(userId + "alert",alert,cacheKeepTime);
          //detailRisk(json,word.msgRisk.detailRisk1);
          break;
        case "\"" + word.msgRisk.summaryRisk.buttonData[1] + "\"":
          //検索結果
          //●●川選択
          detailRisk(json,word.msgRisk.detailRisk2);
          break;
        case "\"" + word.msgRisk.summaryRisk.buttonData[2] + "\"":
          //検索結果
          //●●川選択
          detailRisk(json,word.msgRisk.detailRisk3);
          break;
        case "\"" + word.msgRisk.detailRisk1.evacuation.buttonData + "\"":
          //河川名1の避難情報判定
          //避難情報判定
          alert = cache.get(userId + "alert");
          if(alert==null){
            //outFileLog("キャッシュ取得失敗");
            //outFileLog("非対応文字列")
            cache.remove(userId + CACHE_KEY_ROUTE);
            //cache.put(userId + CACHE_KEY_ROUTE,CACHE_ROUTE_7,cacheKeepTime);
            cont.push(
              {
                "type": "text",
                "text": word.msgOther.unusable.title,
                "weight": "bold",
                "size": "lg",
                "margin": "md"
              },
              {
                "type": "separator",
                "color": "#808080"
              },
              {
                "type": "text",
                "wrap": true,
                "text": "お手数ですが、最初からやり直してください。"
              }
            );
            sendMsgReply(json,word.msgOther.unusable.title,cont);
            break;
          }
          if(!alert.inuCode || alert.inuCode === ""){
            //家屋倒壊地域に該当しない場合、建物の状態を選択
            selectHouse(json,word.msgRisk.selectHouse);
          }else{
            //家屋倒壊地域に該当する場合、即座に避難情報表示
            //outFileLog("inucode true");
            facility = alert.facilityList.join(",").replace(/,/g, "、");
            returnDetailEvac(json,word,"",alert,facility);
          }
          break;
        case "\"" + word.msgRisk.detailRisk2.evacuation.buttonData + "\"":
          //危険度詳細情報
          //避難情報判定
          selectHouse(json,word.msgRisk.selectHouse);
          break;
        case "\"" + word.msgRisk.detailRisk3.evacuation.buttonData + "\"":
          //危険度詳細情報
          //避難情報判定
          selectHouse(json,word.msgRisk.selectHouse);
          break;
        //建物の高さをチェックする
        case "\"" + word.msgRisk.selectHouse.buttonData[0] + "\"":
          buttonData = word.msgRisk.selectHouse.buttonData[0];
          switchDetailEvac(json,word,cache,buttonData,userId);
          break;
        case "\"" + word.msgRisk.selectHouse.buttonData[1] + "\"":
          buttonData = word.msgRisk.selectHouse.buttonData[1];
          switchDetailEvac(json,word,cache,buttonData,userId);
          break;
        case "\"" + word.msgRisk.selectHouse.buttonData[2] + "\"":
          buttonData = word.msgRisk.selectHouse.buttonData[2];
          switchDetailEvac(json,word,cache,buttonData,userId);
          break;
        case "\"" + word.msgRisk.selectHouse.buttonData[3] + "\"":
          buttonData = word.msgRisk.selectHouse.buttonData[3];
          switchDetailEvac(json,word,cache,buttonData,userId);
          break;
        case "\"" + word.msgRisk.selectHouse.buttonData[4] + "\"":
          buttonData = word.msgRisk.selectHouse.buttonData[4];
          switchDetailEvac(json,word,cache,buttonData,userId);
          break;
        case "\"" + word.msgRisk.selectHouse.buttonData[5] + "\"":
          buttonData = word.msgRisk.selectHouse.buttonData[5];
          switchDetailEvac(json,word,cache,buttonData,userId);
          break;
        //木造鉄骨選択
        //全て無視（派生しない）
        case "\"" + word.msgRisk.structureHouse.buttonData[0] + "\"":
        case "\"" + word.msgRisk.structureHouse.buttonData[1] + "\"":
          detailEvacuation(json,word.msgRisk.detailEvacuation);
          break;
        //
        //case "\"" + word.msgRisk.selectWay.buttonData[0] + "\"":
        //  break;
        case "\"" + word.msgRisk.selectWay.buttonData[1] + "\"":
          //住所選択
          cache.put(userId + "STS_NOWREPLY",CACHE_STS_ADDRESS,cacheKeepTime)
          //入力方法サジェスト表示
          aboutPostalcode(json,word.msgRisk.aboutPostalcode);
          break;
        //case "\"" + word.msgEvacuation.selectWay.buttonData[0] + "\"":
        //  break;
        case "\"" + word.msgEvacuation.selectWay.buttonData[1] + "\"":
          aboutPostalcode(json,word.msgEvacuation.aboutPostalcode);
          break;
        case "\"" + word.msgEvacuation.selectLocation.buttonData[0] + "\"":
          msgLink(json,word.msgEvacuation.link);
          break;
        case "\"" + word.msgEvacuation.selectLocation.buttonData[1] + "\"":
          selectWay(json,word.msgEvacuation.selectWay);
          break;
        //case "\"" + word.msgKwb.selectWay.buttonData[0] + "\"":
        //  break;
        case "\"" + word.msgKwb.selectWay.buttonData[1] + "\"":
          aboutPostalcode(json,word.msgKwb.aboutPostalcode);
          break;
        case "\"" + word.msgKwb.selectLocation.buttonData[0] + "\"":
          msgLink(json,word.msgKwb.link);
          break;
        case "\"" + word.msgKwb.selectLocation.buttonData[1] + "\"":
          selectWay(json,word.msgKwb.selectWay);
          break;
        //case "\"" + word.msgNowEvacuation.selectWay.buttonData[0] + "\"":
        //  break;
        case "\"" + word.msgNowEvacuation.selectWay.buttonData[1] + "\"":
          //住所選択、住所指定方法出力
          aboutPostalcode(json,word.msgNowEvacuation.aboutPostalcode);
          break;
        case "\"" + word.msgNowEvacuation.selectLocation.buttonData[0] + "\"":
          //checkRisk(json,word.msgNowEvacuation.checkRisk);
          //Utilities.sleep(WAIT_SECOND * 1000);
          summaryNowEvacuationRisk(json,word.msgNowEvacuation.warnRain);
          //summaryRisk(json,word.msgNowEvacuation.selectRiver);
          //summaryNowEvacuationRisk(json,word.msgNowEvacuation.warnRain);
          break;
        case "\"" + word.msgNowEvacuation.selectLocation.buttonData[1] + "\"":
          selectWay(json,word.msgNowEvacuation.selectWay);
          break;
        case "\"" + word.msgNowEvacuation.selectRiver.buttonData[0] + "\"":
          summaryNowEvacuationRisk(json,word.msgNowEvacuation.overStg1);
          break;
        case "\"" + word.msgNowEvacuation.warnRain.buttonData[0] + "\"":
          summaryRisk(json,word.msgNowEvacuation.selectRiver);
          //summaryNowEvacuationRisk(json,word.msgNowEvacuation.overStg1);
          break;
        case "\"" + word.msgNowEvacuation.overStg1.buttonData[0] + "\"":
          summaryNowEvacuationRisk(json,word.msgNowEvacuation.predStg1);
          break;
        case "\"" + word.msgNowEvacuation.predStg1.buttonData[0] + "\"":
          summaryNowEvacuationRisk(json,word.msgNowEvacuation.predArrival1);
          break;
        case "\"" + word.msgNowEvacuation.predArrival1.buttonData[0] + "\"":
          summaryNowEvacuationRisk(json,word.msgNowEvacuation.predLandslide1);
          break;
        case "\"" + word.msgNowEvacuation.predLandslide1.buttonData[0] + "\"":
          summaryNowEvacuationRisk(json,word.msgNowEvacuation.evacuationShelter1);
          break;
        case "\"" + word.msgNowEvacuation.evacuationShelter1.buttonData[0] + "\"":
          callMap(json,word.msgNowEvacuation.callMap);
          break;
        case "\"" + word.msgNowEvacuation.selectRiver.buttonData[1] + "\"":
          summaryNowEvacuationRisk(json,word.msgNowEvacuation.overStg2);
          //summaryNowEvacuationRisk(json,word.msgNowEvacuation.warnRain2);
          break;
        case "\"" + word.msgNowEvacuation.selectRiver.buttonData[2] + "\"":
          summaryNowEvacuationRisk(json,word.msgNowEvacuation.overStg2);
          //summaryNowEvacuationRisk(json,word.msgNowEvacuation.warnRain2);
          break;
        case "\"" + word.msgNowEvacuation.overStg2.buttonData[0] + "\"":
          summaryNowEvacuationRisk(json,word.msgNowEvacuation.predStg2);
          break;
        case "\"" + word.msgNowEvacuation.predStg2.buttonData[0] + "\"":
          summaryNowEvacuationRisk(json,word.msgNowEvacuation.predArrival2);
          break;
        case "\"" + word.msgNowEvacuation.predArrival2.buttonData[0] + "\"":
          summaryNowEvacuationRisk(json,word.msgNowEvacuation.predLandslide2);
          break;
        case "\"" + word.msgNowEvacuation.predLandslide2.buttonData[0] + "\"":
          summaryNowEvacuationRisk(json,word.msgNowEvacuation.evacuationShelter2);
          break;
        case "\"" + word.msgNowEvacuation.evacuationShelter2.buttonData[0] + "\"":
          callMap(json,word.msgNowEvacuation.callMap);
          break;
      }
  
    }
  
   //outFileLog("doPost:END");
  }

  //川の防災情報URL作成用住所検索
  //中身はreplyFromSheetとほぼ同一
  function locationFromSheet(data,cache,word) {
    //outFileLog("locationFromSheet:START");
    //outFileLog("locationFromSheet:data="+JSON.stringify(data));
    let rtnFacility;
    let rtnAssCode;
    let evacInfoTiming;
    let userMessage = "";
    var userId = data.events[0].source.userId;
    cache.remove(userId + "STS_NOWREPLY");
    if (data.events.length == 0) {
      //outFileLog("replyFromSheet:data.events.lengthが0ルート");
      return [rtnFacility,rtnAssCode];
    }

    // WebHookで受信した応答用Token
    var replyToken = data.events[0].replyToken;replyFromSheet;
    // ユーザから送られてきたデータのタイプ
    let userEventType = data.events[0].type;
    let userMsgType;
    if ( userEventType === "message") {
      userMsgType = data.events[0].message.type;
    }
    else if( userEventType === "postback"){
      //outFileLog("replyFromSheet:postback処理");
      userMessage = cache.get(userId+"message");
      userMsgType = "postback";
    }
    //outFileLog("replyFromSheet:userId="+userId);
    let returnmessages = [];

    let postData;
    let options;

    // 住所CSV読み込み
    let listTwn = getTwnCsv();


    let userPostback = "";
    let otherTypeFlg = "0";//userMsgTypeがtext,location,postbackの場合、0。それ以外の場合、1。

    if (userMsgType == "text") {
      // ユーザーが入力した住所を取得
      userMessage = data.events[0].message.text;
    } else if (userMsgType == "location") {
      //locationの場合、「日本」と「郵便番号」を省いて●●市以降を抽出する
      let userLocation = data.events[0].message.address;
      let idxOta = userLocation.indexOf(STR_CITY);
      let address = userLocation.substr(idxOta);
      userMessage = address.replace(STR_CITY, "");
      //キャッシュのユーザーメッセージを改めて定義
      //cache.remove(userId + "message");
      //cache.put(userId+"message",userMessage,cacheKeepTime);
    }else {
      //postbackがうまくいってない場合
      if(userMessage==null){
        otherTypeFlg = "1";
      }
    }
    //outFileLog("userMessage"+userMessage);


    let idx = userMessage.indexOf(STR_CHOME);

    let chome;
    let banti;
    let msg;

    if (otherTypeFlg === "1") {
      //userMsgTypeがtextでも、locationでもない場合は終了
      //outFileLog("合致情報なし:ルート1");
      returnmessages.push({
        type: "text",
        text:
          "入力された住所に合致する情報が見つかりませんでした。住所か位置情報を再度入力して下さい。",
      });
    } else if (idx >= 0) {
      chome = userMessage.substr(0, idx + STR_CHOME.length);
      // 丁目の漢字変換
      //chome = replacechome(chome);
      // 数字に変換可能な文字列を変換
      // csvの丁目を漢数字から数値に変更したことに伴い、変換関数変更
      chome = replacechomeToNum(chome);

      let str = userMessage.substr(idx + STR_CHOME.length);
      str = TextKan2Num(str);

      let banti = replaceBanti(str);
      let targetList = listTwn.filter(
        (data) => data.townChome == chome && data.banti == banti
      );
      //outFileLog("丁目ありルート");
      //outFileLog("  chome=" + chome);
      //outFileLog("  banti=" + banti);

      if (targetList && targetList.length > 0) {
        //outFileLog("検索ヒット");
        //outFileLog("location:"+targetList[0].lat+","+targetList[0].lon);
        let msg = word.msgKwb.link;
        msg.link = getReturnMsgLink(targetList[0].lat , targetList[0].lon);
        msgLink(data,msg);
        cache.put(userId+"message",userMessage,cacheKeepTime);
        cache.put(userId + "STS_NOWREPLY",CACHE_STS_SUMMARYRISK,cacheKeepTime);
        return ;
      } else {
        //outFileLog("合致情報なし:ルート2");
        returnmessages.push({
          type: "text",
          text:
            "入力された住所に合致する情報が見つかりませんでした。住所か位置情報を再度入力して下さい。",
        });
      }
    } else {
      //outFileLog("丁目なしルート");
      let numIdx = -1;
      let bIdx = userMessage.indexOf(STR_BAN);

      if (bIdx > 0) {
        //outFileLog("番ありルート");
        // 番が含まれている場合は、そこから切り出す
        let strB = userMessage.substr(0, bIdx);
        let strBanti;
        for (let bi = 1; bi < strB.length; bi++) {
          let s = TextKan2Num(strB.substr(strB.length - bi));
          if (isNaN(s)) {
            banti = strBanti;
            chome = strB.substr(0, strB.length - bi + 1);
            break;
          }
          strBanti = s;
        }
      } else {
        // 番がふくまれていない場合は、数値に変換可能かで判断する
        //outFileLog("番なしルート");
        let address = userMessage.replace(/[！-～]/g, function (input) {
          return String.fromCharCode(input.charCodeAt(0) - 0xfee0);
        });

        for (let i = 0; i < address.length; i++) {
          if (!isNaN(address.substr(i, 1))) {
            numIdx = i;
            break;
          }
        }
        chome = userMessage.substr(0, numIdx);
        banti = replaceBanti(address.substr(numIdx));
      }

      let targetList = listTwn.filter(
        (data) => data.townChome == chome && data.banti == banti
      );

      //targetListがない場合、番地を改めて修正
      if (targetList && targetList.length <= 0) {
        //outFileLog("targetListなしルート");
        //outFileLog("replyFromSheet:丁目を含まないデータのルート");
        // 丁目を含まないデータで合致しない場合は、丁目が省略されている事を考慮してデータの照合をする
        numIdx = chome.length + banti.length;
        // 多摩川2-5→丁目[多摩川ニ丁目] 番地[5]となるように変換
        //chome = replacechome(chome + banti) + STR_CHOME;
        // csvの丁目を漢数字から数値に変更したことに伴い、変換関数変更
        chome = replacechomeToNum(chome + banti + STR_CHOME );
        // 丁目として採用した文字以降、数字から始まる場合と、「の」「ー」等が入る場合もある
        let strBanti = userMessage.replace(/[！-～]/g, function (input) {
          return String.fromCharCode(input.charCodeAt(0) - 0xfee0);
        });
        strBanti = strBanti.substr(numIdx);
        strBanti = TextKan2Num(strBanti);

        let idxBanti = -1;
        for (let m = 0; m < strBanti.length; m++) {
          if (isNaN(strBanti.substr(m, 1))) {
            idxBanti = m;
            break;
          }
        }
        strBanti = strBanti.substr(idxBanti);

        for (m = 0; m < strBanti.length; m++) {
          if (!isNaN(strBanti.substr(m, 1))) {
            idxBanti = m;
            break;
          }
        }
        strBanti = strBanti.substr(idxBanti);

        for (m = 0; m < strBanti.length; m++) {
          if (!isNaN(strBanti.substr(m, 1))) {
            idxBanti = m + 1;
          } else {
            break;
          }
        }
        banti = strBanti.substr(0, idxBanti);
        targetList = listTwn.filter(
          (data) => data.townChome == chome && data.banti == banti
        );
      }
      //outFileLog("chome=" + chome);
      //outFileLog("banti=" + banti);

      //ここまでが検索
      if (targetList && targetList.length > 0) {
        //outFileLog("検索ヒット");
        //outFileLog("location:"+targetList[0].lat+","+targetList[0].lon);
        let msg = word.msgKwb.link;
        msg.link = getReturnMsgLink(targetList[0].lat , targetList[0].lon);
        cache.put(userId+"message",userMessage,cacheKeepTime);
        cache.put(userId + "STS_NOWREPLY",CACHE_STS_SUMMARYRISK,cacheKeepTime);
        msgLink(data,msg);
        return;
      } else {
        //それでもtragetListがない場合
        //outFileLog("合致情報なし:ルート3");
        returnmessages.push({
          type: "text",
          text:
            "入力された住所に合致する情報が見つかりませんでした。住所か位置情報を再度入力して下さい。",
        });
      }
    }
    //cache.remove(userId + "STS_NOWREPLY");
    //cache.put(userId + "STS_NOWREPLY",CACHE_STS_SUMMARYRISK,cacheKeepTime);
    return returnmessages;
}

  //建物の高さボタンから情報を受け取って判定
  //判定自体はreturnDetailEvacに記述
  function switchDetailEvac(json,word,cache,buttonData,userId){
    let alert = cache.get(userId + "alert");
    // Logger.log("alert="+alert);
    let facility = alert.facilityList.join(",").replace(/,/g, "、");
    if(alert == null){
      let cont = [];
      cont.push(
        {
          "type": "text",
          "text": word.msgOther.unusable.title,
          "weight": "bold",
          "size": "lg",
          "margin": "md"
        },
        {
          "type": "separator",
          "color": "#808080"
        },
        {
          "type": "text",
          "wrap": true,
          "text": "お手数ですが、最初からやり直してください。"
        }
      );
      sendMsgReply(json,word.msgOther.unusable.title,cont);
      return;
    }
    returnDetailEvac(json,word,buttonData,alert,facility);
  }
  
  //建物避難詳細情報出力
  function returnDetailEvac(json,word,userAns,alert,argFacMsg){
    let msg = word.msgRisk.detailEvacuation;//word.jsonのメッセージ型に従う
    let standby = "自宅外へ避難する必要はありませんが、気象庁や区からの情報を確認し、";
    let holiz = "今いる場所が浸水する可能性があるため、";
    let vart1 = "自宅の一階床上まで浸水する可能性があるため、";
    let vart2 = "自宅の二階まで浸水する可能性があるため、";
    let evac0 = "自宅外へ避難しましょう。"
    let evac1 = "二階以上への垂直避難、もしくは";
    let evac2 = "三階以上への垂直避難、もしくは";
    let evac_standby = "必要に応じて避難してください。";
    let evac_now1 = "家屋が倒壊する可能性がある区域に該当するため、";
    let evac_now2 = "周囲に十分気を付けて、その場を離れましょう。";
    let argAssCode = alert.assCode;

    //避難所が抽出できた時
    if(argFacMsg){
      msg.location.msg[1] = argFacMsg;
    }else{
    //避難所が抽出できなかったとき
      msg.location.msg[1] = "本アプリでは";
      msg.location.msg[2] = "検索できませんでした。";
      msg.location.fontWeight[1] = "regular";
    }

    //家屋倒壊地域かどうか
    if(!alert.inuCode || alert.inuCode === "" || userAns !== ""){
      //outFileLog("userAns:"+userAns);
      //outFileLog("argAssCode:"+argAssCode);
      switch(userAns){
        case word.msgRisk.selectHouse.buttonData[0]:
          //一戸建て平屋
          msg.info.msg[0] = holiz;
          msg.info.msg[1] = evac0;
          break;
        case word.msgRisk.selectHouse.buttonData[1]:
          //一戸建て二階
          //LV2のみ分岐表示表示
          if(argAssCode==2){
            msg.info.msg[0] = vart1;
            msg.info.msg[1] = evac1 + evac0;
          }else{
          msg.info.msg[0] = holiz;
          msg.info.msg[1] = evac0;
          }
          break;
        case word.msgRisk.selectHouse.buttonData[2]:
          //一戸建て三階
            msg.info.msg[0] = vart2;
            msg.info.msg[1] = evac2+evac0;
          break;
        case word.msgRisk.selectHouse.buttonData[3]:
          //集合住宅一階
          msg.info.msg[0] = holiz;
          msg.info.msg[1] = evac0;
          break;
        case word.msgRisk.selectHouse.buttonData[4]:
          //集合住宅二階
          //LV2のみ分岐表示
          if(argAssCode==2){
            msg.info.msg[0] = standby;
            msg.info.msg[1] = evac_standby;
          }
          else{
            msg.info.msg[0] = holiz;
            msg.info.msg[1] = evac0;          
          }
          break;
        case word.msgRisk.selectHouse.buttonData[5]:
          //集合住宅三階以上
            msg.info.msg[0] = standby;
            msg.info.msg[1] = evac_standby;
          break;    
      }
    }else{
      //倒壊該当地域の場合、すぐ逃げるよう指示
      msg.info.msg[0] = evac_now1;
      msg.info.msg[1] = evac_now2;
    }
    detailEvacuation(json,msg);
    return;
  }

  //reply
  //回数制限はないが、ユーザーの送信に対して1回のみ
  function sendMsgReply(data,alttxt,cont) {
    var funcName = arguments.callee.name;
  
    var repToken = data.events[0].replyToken;
    
    var msg = [];
  
    msg.push({
      "type": "flex",
      "altText": alttxt,
      "contents": {
        "type": "carousel",
        "contents": [
          {
            "type": "bubble",
            "body": {
              "type": "box",
              "layout": "vertical",
              "spacing": "sm",
              "paddingTop": "md",
              "paddingBottom": "md",
              "contents": cont
           }
         }
        ]
      }
    });
  
    var postData = {
      "replyToken": repToken,
      "messages": msg,
    };
  
    var headers = {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + ACCESS_TOKEN,
    };
  
    var options = {
      "method": "post",
      "headers": headers,
      "payload": JSON.stringify(postData),
      "muteHttpExceptions" : true,//log出力時に必要
    };
  
    //outFileLog(funcName + ":options=" + JSON.stringify(options));
  
    try {
      var json = UrlFetchApp.fetch(URL_REPLY, options);
      //outFileLog(funcName + ":fetch json="+json);
    } catch(e) {
      //outFileLog(funcName + ":fetch send failed"+e);
    }
  
  };
  
  //push
  //回数制限あり。無料の公式アカウントは200回
  function sendMsgPush(data,alttxt,cont) {
    //outFileLog("send location")
    var funcName = arguments.callee.name;
  
    var userId = data.events[0].source.userId;
    
    var msg = [];
  
    msg.push({
      "type": "flex",
      "altText": alttxt,
      "contents": {
        "type": "carousel",
        "contents": [
          {
            "type": "bubble",
            "body": {
              "type": "box",
              "layout": "vertical",
              "spacing": "sm",
              "paddingTop": "md",
              "paddingBottom": "md",
              "contents": cont
           }
         }
        ]
      }
    });
  
    var headers = {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + ACCESS_TOKEN,
    };
    let postData = {
      "to": userId,
      "messages": msg,
    };
    let options = {
      "method": "post",
      "headers": headers,
      "payload": JSON.stringify(postData),
      "muteHttpExceptions" : true,//log出力時に必要
    };
  
    //outFileLog(funcName + ":options=" + JSON.stringify(options));
  
    //LINE Messaging APIにデータを送信する
    try {
      let json = UrlFetchApp.fetch(URL_PUSH, options);
      //outFileLog(funcName + ":fetch json="+json);
    } catch(e) {
      //outFileLog(funcName + ":fetch e="+e);
    } 
  
  };

  //回数制限はないが、ユーザーの送信に対して1回のみ
  //画像とセット
  function sendMsgImgReply(data,alttxt,msgCont,imgCont) {
    var funcName = arguments.callee.name;
  
    var repToken = data.events[0].replyToken;
    
    var msg = [];
  
    msg.push({
      "type": "flex",
      "altText": alttxt,
      "contents": {
        "type": "carousel",
        "contents": [
          {
            "type": "bubble",
            "body": {
              "type": "box",
              "layout": "vertical",
              "spacing": "sm",
              "paddingTop": "md",
              "paddingBottom": "md",
              "contents": msgCont
           }
          },
          {
            "type": "bubble",
            "body": {
              "type": "box",
              "layout": "vertical",
              "spacing": "sm",
              "paddingTop": "md",
              "paddingBottom": "md",
              "contents": imgCont
            }
          }
        ]
      }
    });
  
    var postData = {
      "replyToken": repToken,
      "messages": msg,
    };
  
    var headers = {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + ACCESS_TOKEN,
    };
  
    var options = {
      "method": "post",
      "headers": headers,
      "payload": JSON.stringify(postData),
      "muteHttpExceptions" : true,//log出力時に必要
    };
  
    //outFileLog(funcName + ":options=" + JSON.stringify(options));
  
    try {
      var json = UrlFetchApp.fetch(URL_REPLY, options);
      //outFileLog(funcName + ":fetch json="+json);
    } catch(e) {
      //outFileLog(funcName + ":fetch e="+e);
    }
  
  };
  
  // JSONファイル取得
  function getJson(fileName) {
    let file = DriveApp.getFilesByName(fileName).next();
    let content = file.getBlob().getDataAsString();
    if (!content) return {};
    let json = JSON.parse(content);
    return json;
  }
  
  // キャッシュ変更
  function makeCache() {
    const cache = CacheService.getUserCache();
    return {
      get: function(key) {
        return JSON.parse(cache.get(key));
      },
      put: function(key, value, sec) {
  
        cache.put(key, JSON.stringify(value), (sec === undefined) ? 120 : sec);
        return value;
      },
      remove: function(key) {
        return JSON.parse(cache.remove(key));
      }
    };
  }
  
  //リスクを調査中メッセージ
  //pushを利用するため現在は未使用
  function checkRisk(json,msg) {
    var funcName = arguments.callee.name;
    //outFileLog(funcName + ":START");
    let cont = [];
    cont.push(
      {
        "type": "text",
        "text": msg.title,
        "weight": "bold",
        "size": "lg",
        "margin": "md"
      },
      {
        "type": "separator",
        "color": "#808080"
      },
      {
        "type": "text",
        "wrap": true,
        "text": msg.msg
      }
    );
    //outFileLog(funcName + ":cont=" + JSON.stringify(cont));
    sendMsgPush(json,msg.title,cont);
  }
  
  //地図、住所→水害リスク
  function summaryRisk(json,msg) {
    var funcName = arguments.callee.name;
    //outFileLog(funcName + ":START");
  
    let cont = [];
  
    cont.push(
      {
        "type": "text",
        "text": msg.title,
        "weight": "bold",
        "size": "lg",
        "margin": "md"
      },
      {
        "type": "separator",
        "color": "#808080"
      },
      {
        "type": "text",
        "wrap": true,
        "text": msg.msg
      },
    );
    
    for (let i = 0; i < msg.buttonName.length; i++) {
      cont.push(
        {
          "type": "text",
          "wrap": true,
          "text": "---------------",
          "size": "xxs",
          "align": "center"
        },
        {
          "type": "button",
          "style": "secondary",
          "height": "sm",
          "action": {
            "type": "postback",
            "label": msg.buttonName[i],
            "data": msg.buttonData[i],
            "displayText": msg.buttonName[i]
          }
        },
      );
  
      if (msg.iconImg[i] == "") {
        cont.push(
          {
            "type": "text",
            "wrap": true,
            "text": msg.buttonSummary[i],
            "weight": "bold"
          },
        );
      } else {
        //outFileLog("icon url:"+msg.iconImg[i]);
        cont.push(
          {
            "type": "box",
            "layout": "baseline",
            "contents": [
              {
                "type": "icon",
                "url": msg.iconImg[i],
                "size": "lg"
              },
              {
                "type": "text",
                "wrap": true,
                "text": msg.buttonSummary[i],
                "weight": "bold"
              },
            ]
          },
        );
      }
    }
  
    //outFileLog(funcName + ":cont=" + JSON.stringify(cont));
  
    sendMsgReply(json,msg.title,cont);
  }
  //判定結果
  function detailRisk(json,msg) {
    var funcName = arguments.callee.name;
  
    //outFileLog(funcName + ":START");
    let msgCont = [];
    let imgCont = [];
    let workCont = [];
  
    for (let i = 0; i < msg.risk.msg.length; i++) {
      workCont.push(
        {
          "type": "span",
          "text": msg.risk.msg[i],
          "weight": msg.risk.fontWeight[i]
        },
      );
    }
  
    msgCont.push(
      {
        "type": "text",
        "text": msg.title,
        "weight": "bold",
        "size": "lg",
        "margin": "md"
      },
      {
        "type": "separator",
        "color": "#808080"
      },
      {
        "type": "text",
        "wrap": true,
        "text": msg.risk.subTitle,
        "weight": "bold",
        "decoration": "underline"
      },
      {
        "type": "text",
        "wrap": true,
        "contents": workCont
      },
      {
        "type": "separator",
        "color": "#808080"
      }
    );
  
    if (msg.evacuation.subTitle != "") {
      msgCont.push(
        {
          "type": "text",
          "text": "\n" + msg.evacuation.subTitle,
          "weight": "bold",
          "size": "md",
          "decoration": "underline",
          "margin": "md"
        },
        {
          "type": "text",
          "wrap": true,
          "text": msg.evacuation.msg
        },
        {
          "type": "button",
          "style": "secondary",
          "height": "sm",
          "action": {
            "type": "postback",
            "label": msg.evacuation.buttonName,
            "data": msg.evacuation.buttonData,
            "displayText": msg.evacuation.buttonName
          }
        },
        {
          "type": "separator",
          "color": "#808080"
        }
      );
    }
  
    msgCont.push(
      {
        "type": "text",
        "text": "\n" + msg.otherRiver.subTitle,
        "weight": "bold",
        "size": "md",
        "decoration": "underline",
        "margin": "md"
      },
      {
        "type": "text",
        "wrap": true,
        "text": msg.otherRiver.msg
      },
    );
  
    for (let i = 0; i < msg.otherRiver.buttonName.length; i++) {
      msgCont.push(
        {
          "type": "button",
          "style": "secondary",
          "height": "sm",
          "action": {
            "type": "postback",
            "label": msg.otherRiver.buttonName[i],
            "data": msg.otherRiver.buttonData[i],
            "displayText": msg.otherRiver.buttonName[i]
          }
        },
      );
    }
  
    //outFileLog(funcName + ":msgCont=" + JSON.stringify(msgCont));
  
    if (msg.risk.imgUrl == "") {
      sendMsgReply(json,msg.title,msgCont);
    } else {
      //outFileLog("use image url");
      imgCont.push(
        {
          "type": "text",
          "text": msg.risk.imgTitle,
          "weight": "bold",
          "size": "md",
          "decoration": "underline",
          "margin": "md"
        },
        {
          "type": "image",
          "size": "full",
          "offsetTop": "md",
          "offsetStart": "md",
          "aspectRatio": "1:1.1",
          "url": msg.risk.imgUrl
        }
      );
      //outFileLog(funcName + ":imgCont=" + JSON.stringify(imgCont));
      sendMsgImgReply(json,msg.title,msgCont,imgCont);
    }
  }
  //避難情報判定 
  function selectHouse(json,msg) {
    var funcName = arguments.callee.name;
    //outFileLog(funcName + ":START");
    let cont = [];
    cont.push(
      {
        "type": "text",
        "text": msg.title,
        "weight": "bold",
        "size": "lg",
        "margin": "md"
      },
      {
        "type": "separator",
        "color": "#808080"
      },
      {
        "type": "text",
        "wrap": true,
        "text": msg.msg
      },
    );
  
    for (let i = 0; i < msg.buttonName.length; i++) {
      cont.push(
        {
          "type": "button",
          "style": "secondary",
          "height": "sm",
          "action": {
            "type": "postback",
            "label": msg.buttonName[i],
            "data": msg.buttonData[i],
            "displayText": msg.buttonName[i]
          }
        },
      );
    }
  
    //outFileLog(funcName + ":cont=" + JSON.stringify(cont));
    sendMsgReply(json,msg.title,cont);
  }
  
  //
  function detailEvacuation(json,msg) {
    var funcName = arguments.callee.name;
    //outFileLog(funcName + ":START");
  
    let cont = [];
    let workInfoCont = [];
    let workLocationCont = [];
  
    for (let i = 0; i < msg.info.msg.length; i++) {
      workInfoCont.push(
        {
          "type": "span",
          "text": msg.info.msg[i],
          "weight": msg.info.fontWeight[i]
        },
      );
    }
  
    for (let i = 0; i < msg.location.msg.length; i++) {
      workLocationCont.push(
        {
          "type": "span",
          "text": msg.location.msg[i],
          "weight": msg.location.fontWeight[i]
        },
      );
    }
  
    cont.push(
      {
        "type": "text",
        "text": msg.title,
        "weight": "bold",
        "size": "lg",
        "margin": "md"
      },
      {
        "type": "separator",
        "color": "#808080"
      },
      {
        "type": "text",
        "wrap": true,
        "contents": workInfoCont
      },
      {
        "type": "text",
        "wrap": true,
        "contents": workLocationCont
      }
    );
    //outFileLog(funcName + ":cont=" + JSON.stringify(cont));
    sendMsgReply(json,msg.title,cont);
  }
  

  function selectWay(json,msg) {
    var funcName = arguments.callee.name;
    //outFileLog(funcName + ":START");
    let cont = [];
    cont.push(
      {
        "type": "text",
        "text": msg.title,
        "weight": "bold",
        "size": "lg",
        "margin": "md"
      },
      {
        "type": "separator",
        "color": "#808080"
      },
      {
        "type": "text",
        "wrap": true,
        "text": msg.msg
      },
    );
  
    for (let i = 0; i < msg.buttonName.length; i++) {
  
      if (msg.buttonUri[i]) {
        cont.push(
          {
            "type": "button",
            "style": "secondary",
            "height": "sm",
            "action": {
              "type": "uri",
              "label": msg.buttonName[i],
              "uri": msg.buttonUri[i]
            }
          },
        );
      } else {
        cont.push(
          {
            "type": "button",
            "style": "secondary",
            "height": "sm",
            "action": {
              "type": "postback",
              "label": msg.buttonName[i],
              "data": msg.buttonData[i],
              "displayText": msg.buttonName[i]
            }
          },
        );
      }
  
    }
  
    //outFileLog(funcName + ":cont=" + JSON.stringify(cont));
      sendMsgReply(json,msg.title,cont);
  }
  
  function aboutPostalcode(json,msg) {
    var funcName = arguments.callee.name;
    //outFileLog(funcName + ":START");
    let cont = [];
    cont.push(
      {
        "type": "text",
        "text": msg.title,
        "weight": "bold",
        "size": "lg",
        "margin": "md"
      },
      {
        "type": "separator",
        "color": "#808080"
      },
      {
        "type": "text",
        "wrap": true,
        "text": msg.msg
      }
    );
    //outFileLog(funcName + ":cont=" + JSON.stringify(cont));
    sendMsgReply(json,msg.title,cont);
  }
  
  function selectLocation(json,msg) {
    var funcName = arguments.callee.name;
    //outFileLog(funcName + ":START");
    //Logger.log(msg);
    //outFileLog("msg:"+msg);

    let cont = [];
  
    cont.push(
      {
        "type": "text",
        "text": msg.title,
        "weight": "bold",
        "size": "lg",
        "margin": "md"
      },
      {
        "type": "separator",
        "color": "#808080"
      },
      {
        "type": "text",
        "wrap": true,
        "text": msg.msg
      },
    );
  
    for (let i = 0; i < msg.buttonName.length; i++) {
      cont.push(
        {
          "type": "button",
          "style": "secondary",
          "height": "sm",
          "adjustMode": "shrink-to-fit",
          "scaling": true,
          "action": {
            "type": "postback",
            "label": msg.buttonName[i],
            "data": msg.buttonData[i],
            "displayText": msg.buttonName[i]
          }
        },
      );
    }
    
    //outFileLog(funcName + ":cont=" + JSON.stringify(cont));
    sendMsgReply(json,msg.title,cont);
  }
  
  function msgLink(json,msg) {
    var funcName = arguments.callee.name;
    //outFileLog(funcName + ":START");
    let cont = [];
    cont.push(
      {
        "type": "text",
        "text": msg.title,
        "weight": "bold",
        "size": "lg",
        "margin": "md"
      },
      {
        "type": "separator",
        "color": "#808080"
      },
      {
        "type": "text",
        "wrap": true,
        "text": msg.msg
      },
      {
        "type": "button",
        "style": "secondary",
        "height": "sm",
        "action": {
          "type": "uri",
          "label": msg.buttonName,
          "uri": msg.link
        }
      }
    );
  
    //outFileLog(funcName + ":cont=" + JSON.stringify(cont));
    sendMsgReply(json,msg.title,cont);
  }
  
  function structureHouse(json,msg) {
    var funcName = arguments.callee.name;
    //outFileLog(funcName + ":START");
    let cont = [];
    cont.push(
      {
        "type": "text",
        "text": msg.title,
        "weight": "bold",
        "size": "lg",
        "margin": "md"
      },
      {
        "type": "separator",
        "color": "#808080"
      },
      {
        "type": "text",
        "wrap": true,
        "text": msg.msg
      },
    );
  
    for (let i = 0; i < msg.buttonName.length; i++) {
      cont.push(
        {
          "type": "button",
          "style": "secondary",
          "height": "sm",
          "action": {
            "type": "postback",
            "label": msg.buttonName[i],
            "data": msg.buttonData[i],
            "displayText": msg.buttonName[i]
          }
        },
      );
    }
  
    //outFileLog(funcName + ":cont=" + JSON.stringify(cont));
    sendMsgReply(json,msg.title,cont);
  }
  
  function summaryNowEvacuationRisk(json,msg) {
    var funcName = arguments.callee.name;
  
    //outFileLog(funcName + ":START");
    let msgCont = [];
    let imgCont = [];
    let workCont = [];
  
    //outFileLog(funcName + ":title set");
    // タイトル
    msgCont.push(
      {
        "type": "text",
        "text": msg.title,
        "weight": "bold",
        "size": "lg",
        "margin": "md"
      },
      {
        "type": "separator",
        "color": "#808080"
      },
    );
  
    //outFileLog(funcName + ":subtitle set");
    // サブタイトル
    if (msg.subTitle != "") {
      if (msg.iconImg == "") {
        msgCont.push(
          {
            "type": "text",
            "wrap": true,
            "text": msg.subTitle,
            "weight": "bold",
            "decoration": "underline"
          },
        );
      } else {
        //outFileLog("icon url:"+msg.iconImg);
        msgCont.push(
          {
            "type": "box",
            "layout": "baseline",
            "contents": [
              {
                "type": "icon",
                "url": msg.iconImg,
                "size": "lg"
              },
              {
                "type": "text",
                "wrap": true,
                "text": msg.subTitle,
                "weight": "bold",
                "decoration": "underline"
              }
            ]
          },
        );
      }
    }
  
    //outFileLog(funcName + ":msg set");
    // メッセージ
    for (let i = 0; i < msg.msg.length; i++) {
      workCont.push(
        {
          "type": "span",
          "text": msg.msg[i],
          "weight": msg.fontWeight[i]
        },
      );
    }
    msgCont.push(
      {
        "type": "text",
        "wrap": true,
        "contents": workCont
      },
    );
    
    //outFileLog(funcName + ":date set");
    // 日時
    if (msg.date != "") {
      msgCont.push(
        {
          "type": "text",
          "wrap": true,
          "text": msg.date,
          "size": "sm",
          "align": "end"
        },
      );
    } 
  
    //outFileLog(funcName + ":link set");
    // リンク
    if (msg.linkUrl != "") {
      msgCont.push(
        {
          "type": "text",
          "wrap": true,
          "text": msg.linkMsg,
          "color": "#0000ff",
          "decoration": "underline",
          "action": {
            "type": "uri",
            "label": "リンク",
            "uri": msg.linkUrl
          }
        },
      );
    }
  
    //outFileLog(funcName + ":button set");
    // ボタン
    for (let i = 0; i < msg.buttonName.length; i++) {
      msgCont.push(
        {
          "type": "text",
          "wrap": true,
          "text": " ",
          "size": "xxs"
        },
        {
          "type": "button",
          "style": "secondary",
          "height": "sm",
          "action": {
            "type": "postback",
            "label": msg.buttonName[i],
            "data": msg.buttonData[i],
            "displayText": msg.buttonName[i]
          }
        },
      );
    }
  
    //outFileLog(funcName + ":msgCont=" + JSON.stringify(msgCont));
  
    // 2枚目
    if (msg.imgUrl == "") {
      sendMsgReply(json,msg.title,msgCont);
      //sendMsgPush(json,msg.title,msgCont);
    } else {
      imgCont.push(
        {
          "type": "text",
          "text": msg.imgTitle,
          "weight": "bold",
          "size": "md",
          "decoration": "underline",
          "margin": "md"
        },
        {
          "type": "image",
          "size": "full",
          "offsetTop": "sm",
          "offsetStart": "sm",
          "aspectRatio": "1:1.1",
          "url": msg.imgUrl
        }
      );
      //outFileLog(funcName + ":imgCont=" + JSON.stringify(imgCont));
      sendMsgImgReply(json,msg.title,msgCont,imgCont);
    }
  }
  
  //今とるべき避難行動の地図情報表示
  function callMap(userData,addressData) {
    var funcName = arguments.callee.name;

    //var userId = userData.events[0].source.userId;
    //replyTokenに変更
    var repToken = userData.events[0].replyToken;
    
    var msg;
  
    var headers = {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + ACCESS_TOKEN,
    };

    msg = [];
    for (let i = 0; i < addressData.name.length; i++) {
      msg.push(
      {
        "type": "location",
        "title": addressData.name[i],
        "address": addressData.address[i],
        "latitude": addressData.lat[i],
        "longitude": addressData.lon[i]
      });
    }
    
    let postData = {
      "replyToken": repToken,
      "messages": msg,
    };
    let options = {
      "method": "post",
      "headers": headers,
      "payload": JSON.stringify(postData),
      "muteHttpExceptions" : true,//log出力時に必要
    };
    //outFileLog(funcName + ":options=" + JSON.stringify(options));
    //LINE Messaging APIにデータを送信する
    try {
      let json = UrlFetchApp.fetch(URL_REPLY, options);
      //outFileLog(funcName + ":fetch json="+json);
    } catch(e) {
      //outFileLog(funcName + ":fetch e="+e);
    }   
  }

// replyFromSheet
//   返却値：
//     建物確認結果用の避難情報メッセージ
//     建物確認結果用の想定区域コード
function replyFromSheet(data,cache,word) {
  //outFileLog("replyFromSheet:START");
  //outFileLog("replyFromSheet:data="+JSON.stringify(data));
  let rtnFacility;
  let rtnAssCode;
  let evacInfoTiming;
  let userMessage = "";
  var userId = data.events[0].source.userId;
  cache.remove(userId + "STS_NOWREPLY");
  if (data.events.length == 0) {
    //outFileLog("replyFromSheet:data.events.lengthが0ルート");
    return [rtnFacility,rtnAssCode];
  }

  // WebHookで受信した応答用Token
  var replyToken = data.events[0].replyToken;replyFromSheet;
  // ユーザから送られてきたデータのタイプ
  let userEventType = data.events[0].type;
  let userMsgType;
  if ( userEventType === "message") {
    userMsgType = data.events[0].message.type;
  }
  else if( userEventType === "postback"){
    //outFileLog("replyFromSheet:postback処理");
    userMessage = cache.get(userId+"message");
    userMsgType = "postback";
  }
  //outFileLog("replyFromSheet:userId="+userId);
  let returnmessages = [];

  let postData;
  let options;

  // 住所CSV読み込み
  let listTwn = getTwnCsv();


  let userPostback = "";
  let otherTypeFlg = "0";//userMsgTypeがtext,location,postbackの場合、0。それ以外の場合、1。

  if (userMsgType == "text") {
    // ユーザーが入力した住所を取得
    userMessage = data.events[0].message.text;
  } else if (userMsgType == "location") {
    //locationの場合、「日本」と「郵便番号」を省いて●●市以降を抽出する
    let userLocation = data.events[0].message.address;
    let idxOta = userLocation.indexOf(STR_CITY);
    let address = userLocation.substr(idxOta);
    userMessage = address.replace(STR_CITY, "");
    //キャッシュのユーザーメッセージを改めて定義
    //cache.remove(userId + "message");
    //cache.put(userId+"message",userMessage,cacheKeepTime);
  }else {
    //postbackがうまくいってない場合
    if(userMessage==null){
      otherTypeFlg = "1";
    }
  }
  //outFileLog("userMessage"+userMessage);


  let idx = userMessage.indexOf(STR_CHOME);

  let chome;
  let banti;

  if (otherTypeFlg === "1") {
    //userMsgTypeがtextでも、locationでもない場合は終了
    //outFileLog("合致情報なし:ルート1");
    returnmessages.push({
      type: "text",
      text:
        "入力された住所に合致する情報が見つかりませんでした。住所か位置情報を再度入力して下さい。",
    });
  } else if (idx >= 0) {
    chome = userMessage.substr(0, idx + STR_CHOME.length);
    // 丁目の漢字変換
    //chome = replacechome(chome);
    // 数字に変換可能な文字列を変換
    // csvの丁目を漢数字から数値に変更したことに伴い、変換関数変更
    chome = replacechomeToNum(chome);

    let str = userMessage.substr(idx + STR_CHOME.length);
    str = TextKan2Num(str);

    let banti = replaceBanti(str);
    let targetList = listTwn.filter(
      (data) => data.townChome == chome && data.banti == banti
    );
    //outFileLog("丁目ありルート");
    //outFileLog("  chome=" + chome);
    //outFileLog("  banti=" + banti);

    if (targetList && targetList.length > 0) {
      //outFileLog("ターゲットリストあり");
      //returnmessages = setRtnMsgWithImg(returnmessages,targetList,chome,banti,cache,userId);
      cache.put(userId+"message",userMessage,cacheKeepTime);
      cache.put(userId + "STS_NOWREPLY",CACHE_STS_SUMMARYRISK,cacheKeepTime);
      returnmessages = makeReply(data,targetList,word,chome,banti,cache,userId);
      // let msgLink = getReturnMsgLink(alert, chome, banti);
      
      return returnmessages;
    } else {
      //outFileLog("合致情報なし:ルート2");
      returnmessages.push({
        type: "text",
        text:
          "入力された住所に合致する情報が見つかりませんでした。住所か位置情報を再度入力して下さい。",
      });
    }
  } else {
    //outFileLog("丁目なしルート");
    let numIdx = -1;
    let bIdx = userMessage.indexOf(STR_BAN);

    if (bIdx > 0) {
      //outFileLog("番ありルート");
      // 番が含まれている場合は、そこから切り出す
      let strB = userMessage.substr(0, bIdx);
      let strBanti;
      for (let bi = 1; bi < strB.length; bi++) {
        let s = TextKan2Num(strB.substr(strB.length - bi));
        if (isNaN(s)) {
          banti = strBanti;
          chome = strB.substr(0, strB.length - bi + 1);
          break;
        }
        strBanti = s;
      }
    } else {
      // 番がふくまれていない場合は、数値に変換可能かで判断する
      //outFileLog("番なしルート");
      let address = userMessage.replace(/[！-～]/g, function (input) {
        return String.fromCharCode(input.charCodeAt(0) - 0xfee0);
      });

      for (let i = 0; i < address.length; i++) {
        if (!isNaN(address.substr(i, 1))) {
          numIdx = i;
          break;
        }
      }
      chome = userMessage.substr(0, numIdx);
      banti = replaceBanti(address.substr(numIdx));
    }

    //outFileLog("chome=" + chome);
    //outFileLog("banti=" + banti);

    let targetList = listTwn.filter(
      (data) => data.townChome == chome && data.banti == banti
    );

    //targetListがない場合、番地を改めて修正
    if (targetList && targetList.length <= 0) {
      //outFileLog("targetListなしルート");
      //outFileLog("replyFromSheet:丁目を含まないデータのルート");
      // 丁目を含まないデータで合致しない場合は、丁目が省略されている事を考慮してデータの照合をする
      numIdx = chome.length + banti.length;
      // 多摩川2-5→丁目[多摩川ニ丁目] 番地[5]となるように変換
      //chome = replacechome(chome + banti) + STR_CHOME;
      // csvの丁目を漢数字から数値に変更したことに伴い、変換関数変更
      chome = replacechomeToNum(chome + banti + STR_CHOME );
      // 丁目として採用した文字以降、数字から始まる場合と、「の」「ー」等が入る場合もある
      let strBanti = userMessage.replace(/[！-～]/g, function (input) {
        return String.fromCharCode(input.charCodeAt(0) - 0xfee0);
      });
      strBanti = strBanti.substr(numIdx);
      strBanti = TextKan2Num(strBanti);

      let idxBanti = -1;
      for (let m = 0; m < strBanti.length; m++) {
        if (isNaN(strBanti.substr(m, 1))) {
          idxBanti = m;
          break;
        }
      }
      strBanti = strBanti.substr(idxBanti);

      for (m = 0; m < strBanti.length; m++) {
        if (!isNaN(strBanti.substr(m, 1))) {
          idxBanti = m;
          break;
        }
      }
      strBanti = strBanti.substr(idxBanti);

      for (m = 0; m < strBanti.length; m++) {
        if (!isNaN(strBanti.substr(m, 1))) {
          idxBanti = m + 1;
        } else {
          break;
        }
      }
      banti = strBanti.substr(0, idxBanti);
      targetList = listTwn.filter(
        (data) => data.townChome == chome && data.banti == banti
      );
    }
    //outFileLog("chome=" + chome);
    //outFileLog("banti=" + banti);
    if (targetList && targetList.length > 0) {
      //住所入力かどうかチェック
      //outFileLog("検索ヒット");
      cache.put(userId+"message",userMessage,cacheKeepTime);
      cache.put(userId + "STS_NOWREPLY",CACHE_STS_SUMMARYRISK,cacheKeepTime);
      returnmessages =  makeReply(data,targetList,word,chome,banti,cache,userId);
      return returnmessages;
    } else {
      //それでもtragetListがない場合
      //outFileLog("合致情報なし:ルート3");
      returnmessages.push({
        type: "text",
        text:
          "入力された住所に合致する情報が見つかりませんでした。住所か位置情報を再度入力して下さい。",
      });
    }
  }
  //cache.remove(userId + "STS_NOWREPLY");
  //cache.put(userId + "STS_NOWREPLY",CACHE_STS_SUMMARYRISK,cacheKeepTime);
  return returnmessages;
}

//全国版の出力に合わせ、メッセージを成形
function makeReply(data,targetList,word,chome,banti,cache,userId){
  let msg = word.msgRisk.summaryRisk;
  msg.msg = cache.get(userId+"message")+"の浸水深は以下の通りです。危険度の詳細な情報は河川名のボタンをクリックしてください。";
  //データ取得
  let alert = getAlertCode(targetList[0].lat, targetList[0].lon, chome);
  //キャッシュに検索結果を保存
  cache.put(userId + "alert",alert,cacheKeepTime+addCacheTime);
  cache.put(userId + "chome",chome,cacheKeepTime+addCacheTime);
  cache.put(userId + "banti",banti,cacheKeepTime+addCacheTime);
  let argFacMsg = alert.facilityList.join(",").replace(/,/g, "、");

  //let assCode = getAssumptionCode(targetList[0].lat, targetList[0].lon);
  let setting = getJson(SETTING_FILENAME);
  let image_url = "";
  let result = "";

  switch(alert.assCode){
    case 1:
      image_url = IMAGE_ASS_LVL1;
      break;
    case 2:
      image_url = IMAGE_ASS_LVL2;
      break;
    case 3:
      image_url = IMAGE_ASS_LVL3;
      break;
    case 4:
      image_url = IMAGE_ASS_LVL4;
      break;
    default:
      image_url = IMAGE_ASS_LVL5;
      break;
  }

  // 浸水深・継続時間が無い場合のメッセージ成形
  if (!alert.assCode || !alert.durCode) {
    result = "本アプリでは、危険度が確認できませんでした。";
  }else{
    result = 
      "浸水深" +
      setting.assumptionLvl[parseInt(alert.assCode)] +
      "です。";
  }
    let nocheck = "本アプリでは、危険度が確認できませんでした。";
    msg.buttonSummary[0]= result;
    msg.buttonName[0] = RIVERNAME1;
    msg.buttonSummary[1]= nocheck;
    msg.buttonName[1] = RIVERNAME2;
    msg.buttonSummary[2]= nocheck;
    msg.buttonName[2] = RIVERNAME3;
    summaryRisk(data,msg);
    return;
}

//LINE Messaging APIを利用してデータを送信する
function replyMsgAPI(returnmessages,replyToken,headers){
  //outFileLog("replyFromSheet:returnmessages="+returnmessages);
  postData = {
    replyToken: replyToken,
    messages: returnmessages,
  };

  options = {
    method: "post",
    headers: headers,
    payload: JSON.stringify(postData),
    muteHttpExceptions : true,//log出力時に必要
  };
  
  //LINE Messaging APIにデータを送信する
  try {
    let res = UrlFetchApp.fetch(URL_REPLY, options);
    //outFileLog("replyFromSheet:res="+res);
  } catch(e) {
    //outFileLog("replyFromSheet eroor:"+e);
  }
}

//検索結果と浸水深イメージ画像を表示する形態に変換
//●●市版のメッセージ成形関数
function setRtnMsgWithImg(returnmessages,targetList,chome,banti,cache,userId){
      let alert = getAlertCode(targetList[0].lat, targetList[0].lon, chome);
      let [msg,facilityMsg,rtnEvacInfoTiming,rtnPtn] = getReturnMsg(alert, chome, banti);
      if (rtnPtn == PTN_NOT_RISK ){
        returnmessages.push({
          type: "text",
          text: msg,
        });
      } else {
        let image_url;
        switch(alert.assCode){
          case 1:
            image_url = IMAGE_ASS_LVL1;
            break;
          case 2:
            image_url = IMAGE_ASS_LVL2;
            break;
          case 3:
            image_url = IMAGE_ASS_LVL3;
            break;
          case 4:
            image_url = IMAGE_ASS_LVL4;
            break;
          default:
            image_url = IMAGE_ASS_LVL5;
            break;
        }
          //outFileLog("画像選択:"+image_url);
        if (cache.get(userId + "STS_NOWREPLY") ===  CACHE_STS_ADRESULT){
          let evacInfoMsg;
          //outFileLog("  replyFromSheet:rtnPtn=" + rtnPtn );
      	  if (rtnPtn == PTN_COLLAPSE ){
      		  evacInfoMsg = MSG_COLLAPSE + "\n" + facilityMsg;
      	  } else if (rtnPtn == PTN_STANDBY ){
      		  evacInfoMsg = MSG_STANDBY + "\n" + facilityMsg;
      	  } else {
            //outFileLog("  replyFromSheet:MSG_HORIZ_EVACルート1");
      		  evacInfoMsg = MSG_HORIZ_EVAC + "\n" + facilityMsg;
      	  } 
          returnmessages.push({
          "type": "flex",
          "altText": "水害リスク判定結果",
          "contents": {
            "type": "carousel",
            "contents": [
              {
                "type": "bubble",
                "body": {
                  "type": "box",
                  "layout": "vertical",
                  "spacing": "sm",
                  "contents": [
                    {
                      "type": "text",
                      "wrap": true,
                      "weight": "bold",
                      "text": msg
                    },
                    {
                      "type": "text",
                      "wrap": true,
                      "text": evacInfoMsg
                    }
                 ]
               }
              },
              {
                "type": "bubble",
                "body": {
                  "type": "box",
                  "layout": "vertical",
                  "spacing": "sm",
                  "paddingTop": "sm",
                  "paddingBottom": "sm",
                  "contents": [
                    {
                      "type": "image",
                      "size":"full",
                      "offsetTop":"sm",
                      "offsetStart":"sm",
                      "aspectRatio": "1:1.1",
                      "url": image_url
                   }
                 ]
               }
              },
            ]
          }});
        } else if (rtnEvacInfoTiming == EVAC_INFO_TIMING_2ND_REPLY ) {
          //避難情報を建物確認結果で返信するため、キャッシュ用に退避
          rtnFacility = facilityMsg;
          rtnAssCode = alert.assCode;
          returnmessages.push({
          "type": "flex",
          "altText": "水害リスク判定結果",
          "contents": {
            "type": "carousel",
            "contents": [
              {
                "type": "bubble",
                "body": {
                  "type": "box",
                  "layout": "vertical",
                  "spacing": "sm",
                  "paddingTop": "md",
                  "paddingBottom": "md",
                  "contents": [
                    {
                      "type": "text",
                      "wrap": true,
                      "weight": "bold",
                      "text": msg
                    },
                    {
                    "type": "separator",
                    "margin": "md",
                    "color": "#ffffff"
                    },
                    {
                      "type": "text",
                      "wrap": true,
                      "text": MSG_QUESTION_CHK
                    },
                    {
                      "type": "button",
                     "style": "secondary",
                     "height": "sm",
                     "action": {
                       "type": "postback",
                       "label": "判定",
                       "data": "acction=判定",
                       "displayText": "判定"
                     }
                   }
                 ]
               }
              },
              {
                "type": "bubble",
                "body": {
                  "type": "box",
                  "layout": "vertical",
                  "spacing": "sm",
                  "paddingTop": "sm",
                  "paddingBottom": "sm",
                  "contents": [
                    {
                      "type": "image",
                      "size":"full",
                      "offsetTop":"sm",
                      "offsetStart":"sm",
                      "aspectRatio": "1:1.1",
                      "url": image_url                    
                    
                   }
                 ]
               }
              },
            ]
          }});          
        }
      }
      return returnmessages;
}

// 丁目の文字列置換
function replacechome(chome) {
  chome = chome.replace(/1/g, "一");
  chome = chome.replace(/2/g, "二");
  chome = chome.replace(/3/g, "三");
  chome = chome.replace(/4/g, "四");
  chome = chome.replace(/5/g, "五");
  chome = chome.replace(/6/g, "六");
  chome = chome.replace(/7/g, "七");
  chome = chome.replace(/8/g, "八");
  chome = chome.replace(/9/g, "九");
  chome = chome.replace(/１/g, "一");
  chome = chome.replace(/２/g, "二");
  chome = chome.replace(/３/g, "三");
  chome = chome.replace(/４/g, "四");
  chome = chome.replace(/５/g, "五");
  chome = chome.replace(/６/g, "六");
  chome = chome.replace(/７/g, "七");
  chome = chome.replace(/８/g, "八");
  chome = chome.replace(/９/g, "九");

  return chome;
}

// 丁目の文字列置換
function replacechomeToNum(chome) {
  chome = chome.replace(/一丁目/g, "1丁目");
  chome = chome.replace(/二丁目/g, "2丁目");
  chome = chome.replace(/三丁目/g, "3丁目");
  chome = chome.replace(/四丁目/g, "4丁目");
  chome = chome.replace(/五丁目/g, "5丁目");
  chome = chome.replace(/六丁目/g, "6丁目");
  chome = chome.replace(/七丁目/g, "7丁目");
  chome = chome.replace(/八丁目/g, "8丁目");
  chome = chome.replace(/九丁目/g, "9丁目");
  chome = chome.replace(/１丁目/g, "1丁目");
  chome = chome.replace(/２丁目/g, "2丁目");
  chome = chome.replace(/３丁目/g, "3丁目");
  chome = chome.replace(/４丁目/g, "4丁目");
  chome = chome.replace(/５丁目/g, "5丁目");
  chome = chome.replace(/６丁目/g, "6丁目");
  chome = chome.replace(/７丁目/g, "7丁目");
  chome = chome.replace(/８丁目/g, "8丁目");
  chome = chome.replace(/９丁目/g, "9丁目");

  return chome;
}

// 番地の取得
function replaceBanti(str) {
  let banti = -1;
  str = str.replace(/[！-～]/g, function (input) {
    return String.fromCharCode(input.charCodeAt(0) - 0xfee0);
  });
  for (let i = 0; i < str.length; i++) {
    if (!isNaN(str.substr(0, i + 1))) {
      banti = str.substr(0, i + 1);
    } else {
      break;
    }
  }

  if (banti >= 0) {
    return banti.replace(/[！-～]/g, function (input) {
      return String.fromCharCode(input.charCodeAt(0) - 0xfee0);
    });
  } else {
    return -1;
  }
  // return banti;
}

// 各種危険コードの取得
//function getAlertCode(lat, lon, chome,riverJson) {
function getAlertCode(lat, lon, chome) {
  let alert = {
    inuCode: "",
    durCode: "",
    assCode: "",
    facilityList: [],
  };

  // 家屋倒壊氾濫の危険区分コードを取得
  // alert.inuCode = getInundationCode(lat, lon,riverJson);
  alert.inuCode = getInundationCode(lat, lon);
  // 継続時間のコードを取得
  // alert.inuCode = getInundationCode(lat, lon,riverJson);
  alert.durCode = getDurationCode(lat, lon);
  // 想定区域のコードを取得
  // alert.inuCode = getInundationCode(lat, lon,riverJson);
  alert.assCode = getAssumptionCode(lat, lon);
  // 避難所の一覧を取得
  let evaList = getShelterList(chome);
  alert.facilityList = evaList.map((v) => v.facilityNm);

  return alert;
}

// 家屋倒壊氾濫の危険区分コードを取得
function getInundationCode(lat, lon) {
  //outFileLog("getInundationCode:START");
  let inundationGeojson = getJson(INUNDATION_FILENAME);
  let points = turf.point([lon, lat]);

  let cord = "";

  for (let feature of inundationGeojson.features) {
    let result = turf.pointsWithinPolygon(points, feature);
    if (result && result.features && result.features.length > 0) {
      //outFileLog("危険区分コード発見")
      cord = feature.properties.A31_405;
      break;
    }
  }

  //outFileLog("  cord=" + cord);
  //outFileLog("getInundationCode:END");
  return cord;
}

// 継続時間のコードを取得
function getDurationCode(lat, lon) {
  //outFileLog("getDurationCode:START");
  let geojson = getJson(DURATION_FILENAME);
  let points = turf.point([lon, lat]);

  let cord = "";

  for (let feature of geojson.features) {
    let result = turf.pointsWithinPolygon(points, feature);
    if (result && result.features && result.features.length > 0) {
    //outFileLog("getDurationCode:feature.properties=" + JSON.stringify(feature.properties));
      //outFileLog("継続時間コード発見")
      cord = feature.properties.A31_305;
      break;
    }
  }

  //outFileLog("  cord=" + cord);
  //outFileLog("getDurationCode:END");
  return cord;
}

// 想定区域のコードを取得
function getAssumptionCode(lat, lon) {
  //outFileLog("getAssumptionCode:START");
  let geojson = getJson(ASSUMPTION_FILENAME);
  let points = turf.point([lon, lat]);

  let cord = "";
  //outFileLog("  getAssumptionCode for文:START");
  for (let feature of geojson.features) {
    let result = turf.pointsWithinPolygon(points, feature);
    if (result && result.features && result.features.length > 0) {
      //outFileLog("想定区域コード発見")
      cord = feature.properties.A31_201;
      break;
    }
  }
  //outFileLog("  cord=" + cord);
  //outFileLog("getAssumptionCode:END");
  return cord;
}

//避難情報判定結果
function getDetailRisk(json,alert,chome,banti,word,riverName){
  let setting = getJson(SETTING_FILENAME);
  let resultFacility = "";
  let evacInfoTiming = EVAC_INFO_TIMING_NO_REPLY; // 避難情報表示タイミング
  let ptn = PTN_OTHER;
  let msg = word.msgRisk.detailRisk1;
  let image_url = "";

  //assCodeに合わせた画像をセット
  switch(alert.assCode){
    case 1:
      image_url = IMAGE_ASS_LVL1;
      break;
    case 2:
      image_url = IMAGE_ASS_LVL2;
      break;
    case 3:
      image_url = IMAGE_ASS_LVL3;
      break;
    case 4:
      image_url = IMAGE_ASS_LVL4;
      break;
    default:
      image_url = IMAGE_ASS_LVL5;
      break;
  }

  msg.risk.imgUrl = image_url;

  if (!alert.assCode || !alert.durCode) {
    msg.risk.msg = [
          "  本アプリでは、",
          "危険度が確認できませんでした。"
        ];
    msg.evacuation.subTitle = "";
    msg.risk.imgUrl = "";
    detailRisk(json,msg);
    return;
  }
  //河川名1の情報
  if(riverName === RIVERNAME1){
    //家屋倒壊
    if (!alert.inuCode || alert.inuCode === "") {
      msg.risk.msg[5] =  "該当しません。";
    } else {
      let setting = getJson(SETTING_FILENAME);
      msg.risk.msg[5] =  "該当します。";
      // "家屋が倒壊する区域に該当します。危険区域区分:" +
      // setting.dangerClass[parseInt(alert.inuCode)];
      ptn = PTN_COLLAPSE;
    }
    // 想定区域（浸水深）のメッセージ成形
    if (alert.assCode && alert.assCode !== "") {
      let setting = getJson(SETTING_FILENAME);
        msg.risk.msg[1] = setting.assumptionLvl[parseInt(alert.assCode)]+"\n";
    }else{
      msg.risk.msg[1] = "データを取得できませんでした。"+"\n";
    }
    // 継続時間のメッセージ成形
    if (alert.durCode && alert.durCode !== "") {
      let setting = getJson(SETTING_FILENAME);
      msg.risk.msg[3] = setting.durationLvl[parseInt(alert.durCode)] + "程度\n";
    }else{
      msg.risk.msg[3] = "データを取得できませんでした。"+"\n";
    }
  detailRisk(json,msg);
  return;
  }
}

// 返却用メッセージの取得
//   返却値：
//     返却用メッセージ
//     避難情報メッセージ
//     避難情報表示タイミング(1:最初の回答,2:質問回答後,0:表示なし)
//     避難情報表示タイミングが1の場合の判定結果パターン
function getReturnMsg(alert, chome, banti) {
  let result = STR_CITY + chome + banti + STR_BANTI + "は、";
  let setting = getJson(SETTING_FILENAME);
  let resultFacility = "";
  let evacInfoTiming = EVAC_INFO_TIMING_NO_REPLY; // 避難情報表示タイミング
  let ptn = PTN_OTHER;

  //outFileLog("getReturnMsg:START"); 

  // 浸水深・継続時間が無い場合のメッセージ成形
  if (!alert.assCode || !alert.durCode) {
    result =
      "該当箇所は、本アプリでは、水害リスクが確認できませんでした。より詳しい水害リスクと避難場所は、●●市のハザードマップで確認してみてください。";
    ptn = PTN_NOT_RISK;
    return [result,resultFacility,evacInfoTiming,ptn];
  }

  evacInfoTiming　= EVAC_INFO_TIMING_1ST_REPLY;

  //outFileLog("  getReturnMsg:alert.inuCode="+alert.inuCode);
  //outFileLog("  getReturnMsg:alert.assCode="+alert.assCode);
  // 家屋倒壊レベルのメッセージ成形
  if (!alert.inuCode || alert.inuCode === "") {
    result = result + "\n家屋が倒壊する区域には該当しません。";
    if (alert.assCode == 1){
      ptn = PTN_STANDBY;
    } else if (alert.assCode == 2 || alert.assCode == 3) {
      evacInfoTiming　= EVAC_INFO_TIMING_2ND_REPLY;
    } else if (alert.assCode == 4 || alert.assCode == 5 || alert.assCode == 6) {
      ptn = PTN_HORIZ_EVAC;
    }
  } else {
    let setting = getJson(SETTING_FILENAME);
    result = result + "\n家屋が倒壊する区域に該当します。";
    // "家屋が倒壊する区域に該当します。危険区域区分:" +
    // setting.dangerClass[parseInt(alert.inuCode)];
    ptn = PTN_COLLAPSE;
  }

  // 想定区域（浸水深）のメッセージ成形
  if (alert.assCode && alert.assCode !== "") {
    let setting = getJson(SETTING_FILENAME);
    result =
      result +
      "\n浸水深" +
      setting.assumptionLvl[parseInt(alert.assCode)] +
      "です。";
  }

  // 継続時間のメッセージ成形
  if (alert.durCode && alert.durCode !== "") {
    let setting = getJson(SETTING_FILENAME);
    result =
      result +
      "\n浸水が継続する時間は" +
      setting.durationLvl[parseInt(alert.durCode)] +
      "程度です。";
  }

  let facility = alert.facilityList.join(",").replace(/,/g, "、");
  if (facility == "") {
    resultFacility = MSG_NO_FACILITY;
  } else {
    resultFacility = "お近くの避難所は、" + facility + "があります。";
  }

  //outFileLog("  getReturnMsg:resultFacility="+resultFacility);  
  //outFileLog("  getReturnMsg:evacInfoTiming="+evacInfoTiming);  
  //outFileLog("getReturnMsg:END");  
  return [result,resultFacility,evacInfoTiming,ptn];
}

// 川の防災情報へのリンクを作成
function getReturnMsgLink(lat,lon) {
  let setting = getJson(SETTING_FILENAME);
  let kawabouURL = `${KWB_URL}zm=${setting.zm}&clat=${lat}&clon=${lon}&viewGrpStg=0`;
  return kawabouURL;
}

// 全角から半角に変換
function toHalfWidth(input) {
  return input.replace(/[！-～]/g, function (input) {
    return String.fromCharCode(input.charCodeAt(0) - 0xfee0);
  });
}

// 丁目・地番CSVの取得
function getTwnCsv() {
  //outFileLog("getTwnCsv:START");
  var file = DriveApp.getFilesByName(TWN_CSV_FILE_NAME).next();
  //var csvData = Utilities.parseCsv(file.getBlob().getDataAsString("utf-8"));
  var csvData = Utilities.parseCsv(file.getBlob().getDataAsString("MS932"));
  // データの整形
  var jsonArray = [];
  csvData.map((row) => {
    let col = 0;
    jsonArray.push({
      prefName: row[col++],
      twnName: row[col++],
      townChome: row[col++],
      townChomeS: row[col++],
      banti: row[col++],
      coordinateNo: row[col++],
      x: row[col++],
      y: row[col++],
      lat: row[col++],
      lon: row[col++],
      residenceDispFlg: row[col++],
      representativeFlg: row[col++],
      updateBeforeFlg: row[col++],
      updateAfterFlg: row[col++],
      zipCord: row[col++],
    });
  });
  //outFileLog("getTwnCsv:END");
  return jsonArray;
}

// 避難所一覧の取得
function getShelterList(chome) {
  var file = DriveApp.getFilesByName(SHELTER_FILENAME).next();
  var csvData = Utilities.parseCsv(file.getBlob().getDataAsString("utf-8"));
  // データの整形
  var jsonArray = [];
  csvData.map((row) => {
    let col = 0;
    jsonArray.push({
      townChomeS: row[col++],
      facilityNm: row[col++],
    });
  });
  var returnList = jsonArray.filter((v) => {
    if (chome.indexOf(v.townChomeS) >= 0) {
      return true;
    }
  });
  return returnList;
}

// JSONファイル取得
function getJson(fileName) {
  //outFileLog("getJson:START");
  let file = DriveApp.getFilesByName(fileName).next();
  //outFileLog(" getJson:step1");
  let content = file.getBlob().getDataAsString();
  //outFileLog(" getJson:step2");
  if (!content) return {};
  //outFileLog(" getJson:step3");
  let json = JSON.parse(content);
  //outFileLog("getJson:END");
  return json;
}

// 数値に変換可能な文字列を数値に変換
function TextKan2Num(text) {
  let ans = ""; // 変換結果を格納する変数（文字列型）
  let tmpstr = ""; // 文字列中の数字部分を一時格納する変数（文字列型）
  for (let i = 0; i < text.length + 1; i++) {
    // 次のif文で文字が数字であるかを識別（Setオブジェクトのhasメソッドで判定）
    if (
      i !== text.length &&
      (suuji1.has(text[i]) || (tmpstr !== "" && suuji2.has(text[i])))
    ) {
      tmpstr += text[i]; // 数字が続く限りtmpstrに格納
    } else {
      // 文字が数字でない場合
      if (tmpstr !== "") {
        // tmpstrに数字が格納されている場合
        ans += Kan2NumCnv(tmpstr, 4); // 上で作成したKan2NumCnv関数で数字に変換してansに結合
        tmpstr = ""; // tmpstrを初期化
      }
      if (i !== text.length) {
        // 最後のループでない場合
        ans += text[i]; // 数字でない文字はそのまま結合
      }
    }
  }
  return ans;
}

// 数値に変換可能な文字列を数値に変換
function Kan2NumCnv(str, n) {
  // 変数の宣言（[let ans = poss = 0, pos, block, tais, tmpstr;]とまとめても良い）
  let ans = 0; // 計算結果を格納する変数（数値型）
  let poss = 0; // 引数strにおける処理開始位置（数値型）
  let pos; // 引数strにおける大数（'十','百','千','万'など）の検索結果位置（数値型）
  let block; // 各桁の数値を格納する変数（数値型）
  let tais; // 大数を格納（文字列型）
  let tmpstr; // 引数strの処理対象部分を一時格納する変数（文字列型）

  if (n === 1) {
    // n == 1 の場合は４桁まで計算
    tais = tais1;
  } else {
    // n == 4 (n != 1) の場合は16桁まで計算（16桁では誤差が生じる）
    n = 4;
    tais = tais2;
  }

  for (let i = 0; i < tais.length; i++) {
    pos = str.indexOf(tais[i]); // indexOf関数は文字の検索位置を返す
    if (pos === -1) {
      // 検索した大数が存在しない場合
      continue; // 何もしないで次のループに
    } else if (pos === poss) {
      // 検索した大数が数字を持たない場合（'千'など）
      block = 1; // '千'は'一千'なので'1'を入れておく
    } else {
      // 検索した大数が数字を持つ場合（'五千'など）
      tmpstr = str.slice(poss, pos); // sliceメソッドは文字列の指定範囲を抽出する
      if (n === 1) {
        block = Number(Kan2Num(tmpstr)); // 1桁の数字を単純変換（上で作成したKan2Num関数を使用）
      } else {
        block = Kan2NumCnv(tmpstr, 1); // 4桁の数字を変換（本関数を再帰的に使用）
      }
    }
    ans += block * 10 ** (n * (tais.length - i)); // ans に演算結果を加算
    poss = pos + 1; // 処理開始位置を次の文字に移す
  }

  // 最後の桁は別途計算して加算
  if (poss !== str.length) {
    tmpstr = str.slice(poss, str.length);
    if (n === 1) {
      ans += Number(Kan2Num(tmpstr));
    } else {
      ans += Kan2NumCnv(tmpstr, 1);
    }
  }
  return ans;
}

// 数値に変換可能な文字列を単純変換
function Kan2Num(str) {
  let tmp; // 定数kansまたはnumsを1文字ずつ格納する変数
  for (let i = 0; i < kans.length; i++) {
    tmp = new RegExp(kans[i], "g"); // RegExpオブジェクトを使用（該当文字を全て変換するため）
    str = str.replace(tmp, i); // replaceメソッドで変換
  }
  for (let i = 0; i < nums.length; i++) {
    tmp = new RegExp(nums[i], "g"); // RegExpオブジェクトを使用（該当文字を全て変換するため）
    str = str.replace(tmp, i); // replaceメソッドで変換
  }
  return str;
}

// キャッシュ変更
function makeCache() {
  const cache = CacheService.getUserCache();
  return {
    get: function(key) {
      return JSON.parse(cache.get(key));
    },
    put: function(key, value, sec) {

      cache.put(key, JSON.stringify(value), (sec === undefined) ? 120 : sec);
      return value;
    },
    remove: function(key) {
      return JSON.parse(cache.remove(key));
    }
  };
}

// 避難情報判定結果のメッセージ出力
function replyEvacuationType(argData,argFacMsg,argAssCode) {
  //outFileLog("replyEvacuationType:START");

  // ユーザから送られてきたデータのタイプ
  var type = argData.events[0].type;
  // WebHookで受信した応答用Token
  var replyToken = argData.events[0].replyToken;

  let postData;
  let options;
  let returnmessages = [];
  let userAns = "";
  let evacMsg = "";

  let headers = {
    "Content-Type": "application/json; charset=UTF-8",
    Authorization: "Bearer " + ACCESS_TOKEN,
  };

  if (type === "message") {
    userAns = argData.events[0].message.text;
  } else {
    userAns = JSON.stringify(argData.events[0].postback.data);
  }

  if (userAns == QUESTION_LIST_BUILDING_TEXT[0] || userAns == QUESTION_LIST_BUILDING_DATA[0]) {
    //outFileLog("  replyEvacuationType:MSG_HORIZ_EVACルート1");
    evacMsg = MSG_HORIZ_EVAC + "\n" + argFacMsg;
  } else if (userAns == QUESTION_LIST_BUILDING_TEXT[1] || userAns == QUESTION_LIST_BUILDING_DATA[1]) {
    if(argAssCode == 2){
      evacMsg = MSG_VERT_EVAC_1 + "\n" + argFacMsg;
    } else {
      //outFileLog("  replyEvacuationType:MSG_HORIZ_EVACルート2");
      evacMsg = MSG_HORIZ_EVAC + "\n" + argFacMsg;
    }
  } else if (userAns == QUESTION_LIST_BUILDING_TEXT[2] || userAns == QUESTION_LIST_BUILDING_DATA[2]) {
    evacMsg = MSG_VERT_EVAC_2 + "\n" + argFacMsg;
  } else if (userAns == QUESTION_LIST_BUILDING_TEXT[3] || userAns == QUESTION_LIST_BUILDING_DATA[3]) {
    //outFileLog("  replyEvacuationType:MSG_HORIZ_EVACルート3");
    evacMsg = MSG_HORIZ_EVAC + "\n" + argFacMsg;
  } else if (userAns == QUESTION_LIST_BUILDING_TEXT[4] || userAns == QUESTION_LIST_BUILDING_DATA[4]) {
    if(argAssCode == 2){
      evacMsg = MSG_STANDBY + "\n" + argFacMsg;
    } else {
      //outFileLog("  replyEvacuationType:MSG_HORIZ_EVACルート4");
      evacMsg = MSG_HORIZ_EVAC + "\n" + argFacMsg;
    }
  } else if (userAns == QUESTION_LIST_BUILDING_TEXT[5] || userAns == QUESTION_LIST_BUILDING_DATA[5]) {
    evacMsg = MSG_STANDBY + "\n" + argFacMsg;
  } else {
    evacMsg = MSG_UNK_ANS;
  }

  returnmessages.push({
    type: "text",
    text: evacMsg,
  });

  postData = {
    replyToken: replyToken,
    messages: returnmessages,
  };

  options = {
    method: "post",
    headers: headers,
    payload: JSON.stringify(postData),
  };

  //LINE Messaging APIにデータを送信する
  let res = UrlFetchApp.fetch(URL_REPLY, options);

  //outFileLog("replyEvacuationType:END");

}

// 建物確認のメッセージ出力
function replyQuestion(argData) {
  // WebHookで受信した応答用Token
  var replyToken = argData.events[0].replyToken;

  let postData;
  let options;
  let returnmessages = [];

  let headers = {
    "Content-Type": "application/json; charset=UTF-8",
    Authorization: "Bearer " + ACCESS_TOKEN,
  };

  returnmessages.push({
  "type": "flex",
  "altText": "建物確認",
  "contents": {
    "type": "carousel",
    "contents": [
      {
        "type": "bubble",
        "body": {
          "type": "box",
          "layout": "vertical",
          "spacing": "sm",
          "contents": [
            {
              "type": "text",
              "wrap": true,
              "text": MSG_QUESTION
            },
            {
              "type": "button",
             "style": "secondary",
             "height": "sm",
             "action": {
               "type": "postback",
               "label": "１．一戸建て平屋",
               "data": "acction=1",
               "displayText": "1"
             }
           },
           {
            "type": "button",
            "style": "secondary",
            "height": "sm",
            "action": {
              "type": "postback",
              "label": "２．一戸建て二階",
              "data": "acction=2",
              "displayText": "2"
            }
          },
          {
            "type": "button",
            "style": "secondary",
            "height": "sm",
            "action": {
              "type": "postback",
              "label": "３．一戸建て三階",
              "data": "acction=3",
              "displayText": "3"
            }
          },
          {
            "type": "button",
            "style": "secondary",
            "height": "sm",
            "action": {
              "type": "postback",
              "label": "４．集合住宅一階",
              "data": "acction=4",
              "displayText": "4"
            }
          },
          {
            "type": "button",
            "style": "secondary",
            "height": "sm",
            "action": {
              "type": "postback",
              "label": "５．集合住宅二階",
              "data": "acction=5",
              "displayText": "5"
            }
          },
          {
            "type": "button",
            "style": "secondary",
            "height": "sm",
            "action": {
              "type": "postback",
              "label": "６．集合住宅三階以上",
              "data": "acction=6",
              "displayText": "6"
           }
          }
          ]
        }
      }
    ]
  }});

  postData = {
    replyToken: replyToken,
    messages: returnmessages,
  };

  options = {
    method: "post",
    headers: headers,
    payload: JSON.stringify(postData),
  };

  //LINE Messaging APIにデータを送信する
  let res = UrlFetchApp.fetch(URL_REPLY, options);

}

// 水害リスク判定中のメッセージ出力
function replyChecking(argData,msg) {
    let questionmessages = [];
    let replyToken = argData.events[0].replyToken;
    //outFileLog("replyChecking 開始");
    //outFileLog("msg:"+msg)

    questionmessages.push({
      "type": "flex",
      "altText": "水害リスク判定中",
      "contents": {
        "type": "bubble",
        "body": {
          "type": "box",
          "layout": "vertical",
          "spacing": "sm",
          "paddingAll": "md",
          "contents": [
            {
              "type": "text",
              "wrap": true,
              "text": msg+"\nの水害リスクを判定中です。"
            }
          ]
        }
      }
    });
      //to: userId,

    let payload = {
      replyToken: replyToken,
      messages: questionmessages,
    };
    let params = {
      method: 'post',
      contentType: 'application/json',
      headers: {
        Authorization: 'Bearer ' + ACCESS_TOKEN
      },
      payload: JSON.stringify(payload)
    };
    //LINE Messaging APIにデータを送信する
    try {
      let resPush = UrlFetchApp.fetch(URL_REPLY, params);
    } catch(e) {
    } 
}


// デバッグ用ログファイル出力
// ※ログ出力先となるスプレッドシートを作成後、シートIDとシート名を設定
const sheetId = '1V7dAOMZs4eJSpZAojIC2yA8YElJ-8_u7GFzIod5rOSk';//スプレッドシートのシートID
const sheetName = 'シート1';//スプレッドシートのシート名
const sh = SpreadsheetApp.openById(sheetId).getSheetByName(sheetName);

function outFileLog(log) {
  let lastRow = sh.getLastRow() + 1;
  sh.getRange(lastRow,1).setValue(new Date());
  sh.getRange(lastRow,2).setValue(log);
}